inline_pass.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  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/util/make_unique.h"
  21. // Indices of operands in SPIR-V instructions
  22. static const int kSpvFunctionCallFunctionId = 2;
  23. static const int kSpvFunctionCallArgumentId = 3;
  24. static const int kSpvReturnValueId = 0;
  25. static const int kSpvLoopMergeContinueTargetIdInIdx = 1;
  26. namespace spvtools {
  27. namespace opt {
  28. uint32_t InlinePass::AddPointerToType(uint32_t type_id,
  29. SpvStorageClass storage_class) {
  30. uint32_t resultId = context()->TakeNextId();
  31. if (resultId == 0) {
  32. return resultId;
  33. }
  34. std::unique_ptr<Instruction> type_inst(
  35. new Instruction(context(), SpvOpTypePointer, 0, resultId,
  36. {{spv_operand_type_t::SPV_OPERAND_TYPE_STORAGE_CLASS,
  37. {uint32_t(storage_class)}},
  38. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {type_id}}}));
  39. context()->AddType(std::move(type_inst));
  40. analysis::Type* pointeeTy;
  41. std::unique_ptr<analysis::Pointer> pointerTy;
  42. std::tie(pointeeTy, pointerTy) =
  43. context()->get_type_mgr()->GetTypeAndPointerType(type_id,
  44. SpvStorageClassFunction);
  45. context()->get_type_mgr()->RegisterType(resultId, *pointerTy);
  46. return resultId;
  47. }
  48. void InlinePass::AddBranch(uint32_t label_id,
  49. std::unique_ptr<BasicBlock>* block_ptr) {
  50. std::unique_ptr<Instruction> newBranch(
  51. new Instruction(context(), SpvOpBranch, 0, 0,
  52. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {label_id}}}));
  53. (*block_ptr)->AddInstruction(std::move(newBranch));
  54. }
  55. void InlinePass::AddBranchCond(uint32_t cond_id, uint32_t true_id,
  56. uint32_t false_id,
  57. std::unique_ptr<BasicBlock>* block_ptr) {
  58. std::unique_ptr<Instruction> newBranch(
  59. new Instruction(context(), SpvOpBranchConditional, 0, 0,
  60. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {cond_id}},
  61. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {true_id}},
  62. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {false_id}}}));
  63. (*block_ptr)->AddInstruction(std::move(newBranch));
  64. }
  65. void InlinePass::AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
  66. std::unique_ptr<BasicBlock>* block_ptr) {
  67. std::unique_ptr<Instruction> newLoopMerge(new Instruction(
  68. context(), SpvOpLoopMerge, 0, 0,
  69. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}},
  70. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {continue_id}},
  71. {spv_operand_type_t::SPV_OPERAND_TYPE_LOOP_CONTROL, {0}}}));
  72. (*block_ptr)->AddInstruction(std::move(newLoopMerge));
  73. }
  74. void InlinePass::AddStore(uint32_t ptr_id, uint32_t val_id,
  75. std::unique_ptr<BasicBlock>* block_ptr) {
  76. std::unique_ptr<Instruction> newStore(
  77. new Instruction(context(), SpvOpStore, 0, 0,
  78. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ptr_id}},
  79. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {val_id}}}));
  80. (*block_ptr)->AddInstruction(std::move(newStore));
  81. }
  82. void InlinePass::AddLoad(uint32_t type_id, uint32_t resultId, uint32_t ptr_id,
  83. std::unique_ptr<BasicBlock>* block_ptr) {
  84. std::unique_ptr<Instruction> newLoad(
  85. new Instruction(context(), SpvOpLoad, type_id, resultId,
  86. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ptr_id}}}));
  87. (*block_ptr)->AddInstruction(std::move(newLoad));
  88. }
  89. std::unique_ptr<Instruction> InlinePass::NewLabel(uint32_t label_id) {
  90. std::unique_ptr<Instruction> newLabel(
  91. new Instruction(context(), SpvOpLabel, 0, label_id, {}));
  92. return newLabel;
  93. }
  94. uint32_t InlinePass::GetFalseId() {
  95. if (false_id_ != 0) return false_id_;
  96. false_id_ = get_module()->GetGlobalValue(SpvOpConstantFalse);
  97. if (false_id_ != 0) return false_id_;
  98. uint32_t boolId = get_module()->GetGlobalValue(SpvOpTypeBool);
  99. if (boolId == 0) {
  100. boolId = context()->TakeNextId();
  101. if (boolId == 0) {
  102. return 0;
  103. }
  104. get_module()->AddGlobalValue(SpvOpTypeBool, boolId, 0);
  105. }
  106. false_id_ = context()->TakeNextId();
  107. if (false_id_ == 0) {
  108. return 0;
  109. }
  110. get_module()->AddGlobalValue(SpvOpConstantFalse, false_id_, boolId);
  111. return false_id_;
  112. }
  113. void InlinePass::MapParams(
  114. Function* calleeFn, BasicBlock::iterator call_inst_itr,
  115. std::unordered_map<uint32_t, uint32_t>* callee2caller) {
  116. int param_idx = 0;
  117. calleeFn->ForEachParam(
  118. [&call_inst_itr, &param_idx, &callee2caller](const Instruction* cpi) {
  119. const uint32_t pid = cpi->result_id();
  120. (*callee2caller)[pid] = call_inst_itr->GetSingleWordOperand(
  121. kSpvFunctionCallArgumentId + param_idx);
  122. ++param_idx;
  123. });
  124. }
  125. bool InlinePass::CloneAndMapLocals(
  126. Function* calleeFn, std::vector<std::unique_ptr<Instruction>>* new_vars,
  127. std::unordered_map<uint32_t, uint32_t>* callee2caller) {
  128. auto callee_block_itr = calleeFn->begin();
  129. auto callee_var_itr = callee_block_itr->begin();
  130. while (callee_var_itr->opcode() == SpvOp::SpvOpVariable) {
  131. std::unique_ptr<Instruction> var_inst(callee_var_itr->Clone(context()));
  132. uint32_t newId = context()->TakeNextId();
  133. if (newId == 0) {
  134. return false;
  135. }
  136. get_decoration_mgr()->CloneDecorations(callee_var_itr->result_id(), newId);
  137. var_inst->SetResultId(newId);
  138. (*callee2caller)[callee_var_itr->result_id()] = newId;
  139. new_vars->push_back(std::move(var_inst));
  140. ++callee_var_itr;
  141. }
  142. return true;
  143. }
  144. uint32_t InlinePass::CreateReturnVar(
  145. Function* calleeFn, std::vector<std::unique_ptr<Instruction>>* new_vars) {
  146. uint32_t returnVarId = 0;
  147. const uint32_t calleeTypeId = calleeFn->type_id();
  148. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  149. assert(type_mgr->GetType(calleeTypeId)->AsVoid() == nullptr &&
  150. "Cannot create a return variable of type void.");
  151. // Find or create ptr to callee return type.
  152. uint32_t returnVarTypeId =
  153. type_mgr->FindPointerToType(calleeTypeId, SpvStorageClassFunction);
  154. if (returnVarTypeId == 0) {
  155. returnVarTypeId = AddPointerToType(calleeTypeId, SpvStorageClassFunction);
  156. if (returnVarTypeId == 0) {
  157. return 0;
  158. }
  159. }
  160. // Add return var to new function scope variables.
  161. returnVarId = context()->TakeNextId();
  162. if (returnVarId == 0) {
  163. return 0;
  164. }
  165. std::unique_ptr<Instruction> var_inst(
  166. new Instruction(context(), SpvOpVariable, returnVarTypeId, returnVarId,
  167. {{spv_operand_type_t::SPV_OPERAND_TYPE_STORAGE_CLASS,
  168. {SpvStorageClassFunction}}}));
  169. new_vars->push_back(std::move(var_inst));
  170. get_decoration_mgr()->CloneDecorations(calleeFn->result_id(), returnVarId);
  171. return returnVarId;
  172. }
  173. bool InlinePass::IsSameBlockOp(const Instruction* inst) const {
  174. return inst->opcode() == SpvOpSampledImage || inst->opcode() == SpvOpImage;
  175. }
  176. bool InlinePass::CloneSameBlockOps(
  177. std::unique_ptr<Instruction>* inst,
  178. std::unordered_map<uint32_t, uint32_t>* postCallSB,
  179. std::unordered_map<uint32_t, Instruction*>* preCallSB,
  180. std::unique_ptr<BasicBlock>* block_ptr) {
  181. return (*inst)->WhileEachInId([&postCallSB, &preCallSB, &block_ptr,
  182. this](uint32_t* iid) {
  183. const auto mapItr = (*postCallSB).find(*iid);
  184. if (mapItr == (*postCallSB).end()) {
  185. const auto mapItr2 = (*preCallSB).find(*iid);
  186. if (mapItr2 != (*preCallSB).end()) {
  187. // Clone pre-call same-block ops, map result id.
  188. const Instruction* inInst = mapItr2->second;
  189. std::unique_ptr<Instruction> sb_inst(inInst->Clone(context()));
  190. if (!CloneSameBlockOps(&sb_inst, postCallSB, preCallSB, block_ptr)) {
  191. return false;
  192. }
  193. const uint32_t rid = sb_inst->result_id();
  194. const uint32_t nid = context()->TakeNextId();
  195. if (nid == 0) {
  196. return false;
  197. }
  198. get_decoration_mgr()->CloneDecorations(rid, nid);
  199. sb_inst->SetResultId(nid);
  200. (*postCallSB)[rid] = nid;
  201. *iid = nid;
  202. (*block_ptr)->AddInstruction(std::move(sb_inst));
  203. }
  204. } else {
  205. // Reset same-block op operand.
  206. *iid = mapItr->second;
  207. }
  208. return true;
  209. });
  210. }
  211. bool InlinePass::GenInlineCode(
  212. std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
  213. std::vector<std::unique_ptr<Instruction>>* new_vars,
  214. BasicBlock::iterator call_inst_itr,
  215. UptrVectorIterator<BasicBlock> call_block_itr) {
  216. // Map from all ids in the callee to their equivalent id in the caller
  217. // as callee instructions are copied into caller.
  218. std::unordered_map<uint32_t, uint32_t> callee2caller;
  219. // Pre-call same-block insts
  220. std::unordered_map<uint32_t, Instruction*> preCallSB;
  221. // Post-call same-block op ids
  222. std::unordered_map<uint32_t, uint32_t> postCallSB;
  223. // Invalidate the def-use chains. They are not kept up to date while
  224. // inlining. However, certain calls try to keep them up-to-date if they are
  225. // valid. These operations can fail.
  226. context()->InvalidateAnalyses(IRContext::kAnalysisDefUse);
  227. Function* calleeFn = id2function_[call_inst_itr->GetSingleWordOperand(
  228. kSpvFunctionCallFunctionId)];
  229. // Check for multiple returns in the callee.
  230. auto fi = early_return_funcs_.find(calleeFn->result_id());
  231. const bool earlyReturn = fi != early_return_funcs_.end();
  232. // Map parameters to actual arguments.
  233. MapParams(calleeFn, call_inst_itr, &callee2caller);
  234. // Define caller local variables for all callee variables and create map to
  235. // them.
  236. if (!CloneAndMapLocals(calleeFn, new_vars, &callee2caller)) {
  237. return false;
  238. }
  239. // Create return var if needed.
  240. const uint32_t calleeTypeId = calleeFn->type_id();
  241. uint32_t returnVarId = 0;
  242. analysis::Type* calleeType = context()->get_type_mgr()->GetType(calleeTypeId);
  243. if (calleeType->AsVoid() == nullptr) {
  244. returnVarId = CreateReturnVar(calleeFn, new_vars);
  245. if (returnVarId == 0) {
  246. return false;
  247. }
  248. }
  249. // Create set of callee result ids. Used to detect forward references
  250. std::unordered_set<uint32_t> callee_result_ids;
  251. calleeFn->ForEachInst([&callee_result_ids](const Instruction* cpi) {
  252. const uint32_t rid = cpi->result_id();
  253. if (rid != 0) callee_result_ids.insert(rid);
  254. });
  255. // If the caller is in a single-block loop, and the callee has multiple
  256. // blocks, then the normal inlining logic will place the OpLoopMerge in
  257. // the last of several blocks in the loop. Instead, it should be placed
  258. // at the end of the first block. First determine if the caller is in a
  259. // single block loop. We'll wait to move the OpLoopMerge until the end
  260. // of the regular inlining logic, and only if necessary.
  261. bool caller_is_single_block_loop = false;
  262. bool caller_is_loop_header = false;
  263. if (auto* loop_merge = call_block_itr->GetLoopMergeInst()) {
  264. caller_is_loop_header = true;
  265. caller_is_single_block_loop =
  266. call_block_itr->id() ==
  267. loop_merge->GetSingleWordInOperand(kSpvLoopMergeContinueTargetIdInIdx);
  268. }
  269. bool callee_begins_with_structured_header =
  270. (*(calleeFn->begin())).GetMergeInst() != nullptr;
  271. // Clone and map callee code. Copy caller block code to beginning of
  272. // first block and end of last block.
  273. bool prevInstWasReturn = false;
  274. uint32_t singleTripLoopHeaderId = 0;
  275. uint32_t singleTripLoopContinueId = 0;
  276. uint32_t returnLabelId = 0;
  277. bool multiBlocks = false;
  278. // new_blk_ptr is a new basic block in the caller. New instructions are
  279. // written to it. It is created when we encounter the OpLabel
  280. // of the first callee block. It is appended to new_blocks only when
  281. // it is complete.
  282. std::unique_ptr<BasicBlock> new_blk_ptr;
  283. bool successful = calleeFn->WhileEachInst(
  284. [&new_blocks, &callee2caller, &call_block_itr, &call_inst_itr,
  285. &new_blk_ptr, &prevInstWasReturn, &returnLabelId, &returnVarId,
  286. caller_is_loop_header, callee_begins_with_structured_header,
  287. &calleeTypeId, &multiBlocks, &postCallSB, &preCallSB, earlyReturn,
  288. &singleTripLoopHeaderId, &singleTripLoopContinueId, &callee_result_ids,
  289. this](const Instruction* cpi) {
  290. switch (cpi->opcode()) {
  291. case SpvOpFunction:
  292. case SpvOpFunctionParameter:
  293. // Already processed
  294. break;
  295. case SpvOpVariable:
  296. if (cpi->NumInOperands() == 2) {
  297. assert(callee2caller.count(cpi->result_id()) &&
  298. "Expected the variable to have already been mapped.");
  299. uint32_t new_var_id = callee2caller.at(cpi->result_id());
  300. // The initializer must be a constant or global value. No mapped
  301. // should be used.
  302. uint32_t val_id = cpi->GetSingleWordInOperand(1);
  303. AddStore(new_var_id, val_id, &new_blk_ptr);
  304. }
  305. break;
  306. case SpvOpUnreachable:
  307. case SpvOpKill: {
  308. // Generate a return label so that we split the block with the
  309. // function call. Copy the terminator into the new block.
  310. if (returnLabelId == 0) {
  311. returnLabelId = context()->TakeNextId();
  312. if (returnLabelId == 0) {
  313. return false;
  314. }
  315. }
  316. std::unique_ptr<Instruction> terminator(
  317. new Instruction(context(), cpi->opcode(), 0, 0, {}));
  318. new_blk_ptr->AddInstruction(std::move(terminator));
  319. break;
  320. }
  321. case SpvOpLabel: {
  322. // If previous instruction was early return, insert branch
  323. // instruction to return block.
  324. if (prevInstWasReturn) {
  325. if (returnLabelId == 0) {
  326. returnLabelId = context()->TakeNextId();
  327. if (returnLabelId == 0) {
  328. return false;
  329. }
  330. }
  331. AddBranch(returnLabelId, &new_blk_ptr);
  332. prevInstWasReturn = false;
  333. }
  334. // Finish current block (if it exists) and get label for next block.
  335. uint32_t labelId;
  336. bool firstBlock = false;
  337. if (new_blk_ptr != nullptr) {
  338. new_blocks->push_back(std::move(new_blk_ptr));
  339. // If result id is already mapped, use it, otherwise get a new
  340. // one.
  341. const uint32_t rid = cpi->result_id();
  342. const auto mapItr = callee2caller.find(rid);
  343. labelId = (mapItr != callee2caller.end())
  344. ? mapItr->second
  345. : context()->TakeNextId();
  346. if (labelId == 0) {
  347. return false;
  348. }
  349. } else {
  350. // First block needs to use label of original block
  351. // but map callee label in case of phi reference.
  352. labelId = call_block_itr->id();
  353. callee2caller[cpi->result_id()] = labelId;
  354. firstBlock = true;
  355. }
  356. // Create first/next block.
  357. new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(labelId));
  358. if (firstBlock) {
  359. // Copy contents of original caller block up to call instruction.
  360. for (auto cii = call_block_itr->begin(); cii != call_inst_itr;
  361. cii = call_block_itr->begin()) {
  362. Instruction* inst = &*cii;
  363. inst->RemoveFromList();
  364. std::unique_ptr<Instruction> cp_inst(inst);
  365. // Remember same-block ops for possible regeneration.
  366. if (IsSameBlockOp(&*cp_inst)) {
  367. auto* sb_inst_ptr = cp_inst.get();
  368. preCallSB[cp_inst->result_id()] = sb_inst_ptr;
  369. }
  370. new_blk_ptr->AddInstruction(std::move(cp_inst));
  371. }
  372. if (caller_is_loop_header &&
  373. callee_begins_with_structured_header) {
  374. // We can't place both the caller's merge instruction and
  375. // another merge instruction in the same block. So split the
  376. // calling block. Insert an unconditional branch to a new guard
  377. // block. Later, once we know the ID of the last block, we
  378. // will move the caller's OpLoopMerge from the last generated
  379. // block into the first block. We also wait to avoid
  380. // invalidating various iterators.
  381. const auto guard_block_id = context()->TakeNextId();
  382. if (guard_block_id == 0) {
  383. return false;
  384. }
  385. AddBranch(guard_block_id, &new_blk_ptr);
  386. new_blocks->push_back(std::move(new_blk_ptr));
  387. // Start the next block.
  388. new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(guard_block_id));
  389. // Reset the mapping of the callee's entry block to point to
  390. // the guard block. Do this so we can fix up phis later on to
  391. // satisfy dominance.
  392. callee2caller[cpi->result_id()] = guard_block_id;
  393. }
  394. // If callee has early return, insert a header block for
  395. // single-trip loop that will encompass callee code. Start
  396. // postheader block.
  397. //
  398. // Note: Consider the following combination:
  399. // - the caller is a single block loop
  400. // - the callee does not begin with a structure header
  401. // - the callee has multiple returns.
  402. // We still need to split the caller block and insert a guard
  403. // block. But we only need to do it once. We haven't done it yet,
  404. // but the single-trip loop header will serve the same purpose.
  405. if (earlyReturn) {
  406. singleTripLoopHeaderId = context()->TakeNextId();
  407. if (singleTripLoopHeaderId == 0) {
  408. return false;
  409. }
  410. AddBranch(singleTripLoopHeaderId, &new_blk_ptr);
  411. new_blocks->push_back(std::move(new_blk_ptr));
  412. new_blk_ptr =
  413. MakeUnique<BasicBlock>(NewLabel(singleTripLoopHeaderId));
  414. returnLabelId = context()->TakeNextId();
  415. singleTripLoopContinueId = context()->TakeNextId();
  416. if (returnLabelId == 0 || singleTripLoopContinueId == 0) {
  417. return false;
  418. }
  419. AddLoopMerge(returnLabelId, singleTripLoopContinueId,
  420. &new_blk_ptr);
  421. uint32_t postHeaderId = context()->TakeNextId();
  422. if (postHeaderId == 0) {
  423. return false;
  424. }
  425. AddBranch(postHeaderId, &new_blk_ptr);
  426. new_blocks->push_back(std::move(new_blk_ptr));
  427. new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(postHeaderId));
  428. multiBlocks = true;
  429. // Reset the mapping of the callee's entry block to point to
  430. // the post-header block. Do this so we can fix up phis later
  431. // on to satisfy dominance.
  432. callee2caller[cpi->result_id()] = postHeaderId;
  433. }
  434. } else {
  435. multiBlocks = true;
  436. }
  437. } break;
  438. case SpvOpReturnValue: {
  439. // Store return value to return variable.
  440. assert(returnVarId != 0);
  441. uint32_t valId = cpi->GetInOperand(kSpvReturnValueId).words[0];
  442. const auto mapItr = callee2caller.find(valId);
  443. if (mapItr != callee2caller.end()) {
  444. valId = mapItr->second;
  445. }
  446. AddStore(returnVarId, valId, &new_blk_ptr);
  447. // Remember we saw a return; if followed by a label, will need to
  448. // insert branch.
  449. prevInstWasReturn = true;
  450. } break;
  451. case SpvOpReturn: {
  452. // Remember we saw a return; if followed by a label, will need to
  453. // insert branch.
  454. prevInstWasReturn = true;
  455. } break;
  456. case SpvOpFunctionEnd: {
  457. // If there was an early return, we generated a return label id
  458. // for it. Now we have to generate the return block with that Id.
  459. if (returnLabelId != 0) {
  460. // If previous instruction was return, insert branch instruction
  461. // to return block.
  462. if (prevInstWasReturn) AddBranch(returnLabelId, &new_blk_ptr);
  463. if (earlyReturn) {
  464. // If we generated a loop header for the single-trip loop
  465. // to accommodate early returns, insert the continue
  466. // target block now, with a false branch back to the loop
  467. // header.
  468. new_blocks->push_back(std::move(new_blk_ptr));
  469. new_blk_ptr =
  470. MakeUnique<BasicBlock>(NewLabel(singleTripLoopContinueId));
  471. uint32_t false_id = GetFalseId();
  472. if (false_id == 0) {
  473. return false;
  474. }
  475. AddBranchCond(false_id, singleTripLoopHeaderId, returnLabelId,
  476. &new_blk_ptr);
  477. }
  478. // Generate the return block.
  479. new_blocks->push_back(std::move(new_blk_ptr));
  480. new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(returnLabelId));
  481. multiBlocks = true;
  482. }
  483. // Load return value into result id of call, if it exists.
  484. if (returnVarId != 0) {
  485. const uint32_t resId = call_inst_itr->result_id();
  486. assert(resId != 0);
  487. AddLoad(calleeTypeId, resId, returnVarId, &new_blk_ptr);
  488. }
  489. // Copy remaining instructions from caller block.
  490. for (Instruction* inst = call_inst_itr->NextNode(); inst;
  491. inst = call_inst_itr->NextNode()) {
  492. inst->RemoveFromList();
  493. std::unique_ptr<Instruction> cp_inst(inst);
  494. // If multiple blocks generated, regenerate any same-block
  495. // instruction that has not been seen in this last block.
  496. if (multiBlocks) {
  497. if (!CloneSameBlockOps(&cp_inst, &postCallSB, &preCallSB,
  498. &new_blk_ptr)) {
  499. return false;
  500. }
  501. // Remember same-block ops in this block.
  502. if (IsSameBlockOp(&*cp_inst)) {
  503. const uint32_t rid = cp_inst->result_id();
  504. postCallSB[rid] = rid;
  505. }
  506. }
  507. new_blk_ptr->AddInstruction(std::move(cp_inst));
  508. }
  509. // Finalize inline code.
  510. new_blocks->push_back(std::move(new_blk_ptr));
  511. } break;
  512. default: {
  513. // Copy callee instruction and remap all input Ids.
  514. std::unique_ptr<Instruction> cp_inst(cpi->Clone(context()));
  515. bool succeeded = cp_inst->WhileEachInId(
  516. [&callee2caller, &callee_result_ids, this](uint32_t* iid) {
  517. const auto mapItr = callee2caller.find(*iid);
  518. if (mapItr != callee2caller.end()) {
  519. *iid = mapItr->second;
  520. } else if (callee_result_ids.find(*iid) !=
  521. callee_result_ids.end()) {
  522. // Forward reference. Allocate a new id, map it,
  523. // use it and check for it when remapping result ids
  524. const uint32_t nid = context()->TakeNextId();
  525. if (nid == 0) {
  526. return false;
  527. }
  528. callee2caller[*iid] = nid;
  529. *iid = nid;
  530. }
  531. return true;
  532. });
  533. if (!succeeded) {
  534. return false;
  535. }
  536. // If result id is non-zero, remap it. If already mapped, use mapped
  537. // value, else use next id.
  538. const uint32_t rid = cp_inst->result_id();
  539. if (rid != 0) {
  540. const auto mapItr = callee2caller.find(rid);
  541. uint32_t nid;
  542. if (mapItr != callee2caller.end()) {
  543. nid = mapItr->second;
  544. } else {
  545. nid = context()->TakeNextId();
  546. if (nid == 0) {
  547. return false;
  548. }
  549. callee2caller[rid] = nid;
  550. }
  551. cp_inst->SetResultId(nid);
  552. get_decoration_mgr()->CloneDecorations(rid, nid);
  553. }
  554. new_blk_ptr->AddInstruction(std::move(cp_inst));
  555. } break;
  556. }
  557. return true;
  558. });
  559. if (!successful) {
  560. return false;
  561. }
  562. if (caller_is_loop_header && (new_blocks->size() > 1)) {
  563. // Move the OpLoopMerge from the last block back to the first, where
  564. // it belongs.
  565. auto& first = new_blocks->front();
  566. auto& last = new_blocks->back();
  567. assert(first != last);
  568. // Insert a modified copy of the loop merge into the first block.
  569. auto loop_merge_itr = last->tail();
  570. --loop_merge_itr;
  571. assert(loop_merge_itr->opcode() == SpvOpLoopMerge);
  572. std::unique_ptr<Instruction> cp_inst(loop_merge_itr->Clone(context()));
  573. if (caller_is_single_block_loop) {
  574. // Also, update its continue target to point to the last block.
  575. cp_inst->SetInOperand(kSpvLoopMergeContinueTargetIdInIdx, {last->id()});
  576. }
  577. first->tail().InsertBefore(std::move(cp_inst));
  578. // Remove the loop merge from the last block.
  579. loop_merge_itr->RemoveFromList();
  580. delete &*loop_merge_itr;
  581. }
  582. // Update block map given replacement blocks.
  583. for (auto& blk : *new_blocks) {
  584. id2block_[blk->id()] = &*blk;
  585. }
  586. return true;
  587. }
  588. bool InlinePass::IsInlinableFunctionCall(const Instruction* inst) {
  589. if (inst->opcode() != SpvOp::SpvOpFunctionCall) return false;
  590. const uint32_t calleeFnId =
  591. inst->GetSingleWordOperand(kSpvFunctionCallFunctionId);
  592. const auto ci = inlinable_.find(calleeFnId);
  593. return ci != inlinable_.cend();
  594. }
  595. void InlinePass::UpdateSucceedingPhis(
  596. std::vector<std::unique_ptr<BasicBlock>>& new_blocks) {
  597. const auto firstBlk = new_blocks.begin();
  598. const auto lastBlk = new_blocks.end() - 1;
  599. const uint32_t firstId = (*firstBlk)->id();
  600. const uint32_t lastId = (*lastBlk)->id();
  601. const BasicBlock& const_last_block = *lastBlk->get();
  602. const_last_block.ForEachSuccessorLabel(
  603. [&firstId, &lastId, this](const uint32_t succ) {
  604. BasicBlock* sbp = this->id2block_[succ];
  605. sbp->ForEachPhiInst([&firstId, &lastId](Instruction* phi) {
  606. phi->ForEachInId([&firstId, &lastId](uint32_t* id) {
  607. if (*id == firstId) *id = lastId;
  608. });
  609. });
  610. });
  611. }
  612. bool InlinePass::HasNoReturnInStructuredConstruct(Function* func) {
  613. // If control not structured, do not do loop/return analysis
  614. // TODO: Analyze returns in non-structured control flow
  615. if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
  616. return false;
  617. const auto structured_analysis = context()->GetStructuredCFGAnalysis();
  618. // Search for returns in structured construct.
  619. bool return_in_construct = false;
  620. for (auto& blk : *func) {
  621. auto terminal_ii = blk.cend();
  622. --terminal_ii;
  623. if (spvOpcodeIsReturn(terminal_ii->opcode()) &&
  624. structured_analysis->ContainingConstruct(blk.id()) != 0) {
  625. return_in_construct = true;
  626. break;
  627. }
  628. }
  629. return !return_in_construct;
  630. }
  631. bool InlinePass::HasNoReturnInLoop(Function* func) {
  632. // If control not structured, do not do loop/return analysis
  633. // TODO: Analyze returns in non-structured control flow
  634. if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
  635. return false;
  636. const auto structured_analysis = context()->GetStructuredCFGAnalysis();
  637. // Search for returns in structured construct.
  638. bool return_in_loop = false;
  639. for (auto& blk : *func) {
  640. auto terminal_ii = blk.cend();
  641. --terminal_ii;
  642. if (spvOpcodeIsReturn(terminal_ii->opcode()) &&
  643. structured_analysis->ContainingLoop(blk.id()) != 0) {
  644. return_in_loop = true;
  645. break;
  646. }
  647. }
  648. return !return_in_loop;
  649. }
  650. void InlinePass::AnalyzeReturns(Function* func) {
  651. if (HasNoReturnInLoop(func)) {
  652. no_return_in_loop_.insert(func->result_id());
  653. if (!HasNoReturnInStructuredConstruct(func))
  654. early_return_funcs_.insert(func->result_id());
  655. }
  656. }
  657. bool InlinePass::IsInlinableFunction(Function* func) {
  658. // We can only inline a function if it has blocks.
  659. if (func->cbegin() == func->cend()) return false;
  660. // Do not inline functions with returns in loops. Currently early return
  661. // functions are inlined by wrapping them in a one trip loop and implementing
  662. // the returns as a branch to the loop's merge block. However, this can only
  663. // done validly if the return was not in a loop in the original function.
  664. // Also remember functions with multiple (early) returns.
  665. AnalyzeReturns(func);
  666. if (no_return_in_loop_.find(func->result_id()) == no_return_in_loop_.cend()) {
  667. return false;
  668. }
  669. if (func->IsRecursive()) {
  670. return false;
  671. }
  672. // Do not inline functions with an OpKill because they may be inlined into a
  673. // continue construct.
  674. bool has_opkill = !func->WhileEachInst(
  675. [](Instruction* inst) { return inst->opcode() != SpvOpKill; });
  676. if (has_opkill) {
  677. return false;
  678. }
  679. return true;
  680. }
  681. void InlinePass::InitializeInline() {
  682. false_id_ = 0;
  683. // clear collections
  684. id2function_.clear();
  685. id2block_.clear();
  686. inlinable_.clear();
  687. no_return_in_loop_.clear();
  688. early_return_funcs_.clear();
  689. for (auto& fn : *get_module()) {
  690. // Initialize function and block maps.
  691. id2function_[fn.result_id()] = &fn;
  692. for (auto& blk : fn) {
  693. id2block_[blk.id()] = &blk;
  694. }
  695. // Compute inlinability
  696. if (IsInlinableFunction(&fn)) inlinable_.insert(fn.result_id());
  697. }
  698. }
  699. InlinePass::InlinePass() {}
  700. } // namespace opt
  701. } // namespace spvtools