inline_pass.cpp 30 KB

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