ir_builder.h 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. // Copyright (c) 2018 Google Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef SOURCE_OPT_IR_BUILDER_H_
  15. #define SOURCE_OPT_IR_BUILDER_H_
  16. #include <limits>
  17. #include <memory>
  18. #include <utility>
  19. #include <vector>
  20. #include "source/opt/basic_block.h"
  21. #include "source/opt/constants.h"
  22. #include "source/opt/instruction.h"
  23. #include "source/opt/ir_context.h"
  24. namespace spvtools {
  25. namespace opt {
  26. // In SPIR-V, ids are encoded as uint16_t, this id is guaranteed to be always
  27. // invalid.
  28. constexpr uint32_t kInvalidId = std::numeric_limits<uint32_t>::max();
  29. // Helper class to abstract instruction construction and insertion.
  30. // The instruction builder can preserve the following analyses (specified via
  31. // the constructors):
  32. // - Def-use analysis
  33. // - Instruction to block analysis
  34. class InstructionBuilder {
  35. public:
  36. using InsertionPointTy = BasicBlock::iterator;
  37. // Creates an InstructionBuilder, all new instructions will be inserted before
  38. // the instruction |insert_before|.
  39. InstructionBuilder(
  40. IRContext* context, Instruction* insert_before,
  41. IRContext::Analysis preserved_analyses = IRContext::kAnalysisNone)
  42. : InstructionBuilder(context, context->get_instr_block(insert_before),
  43. InsertionPointTy(insert_before),
  44. preserved_analyses) {}
  45. // Creates an InstructionBuilder, all new instructions will be inserted at the
  46. // end of the basic block |parent_block|.
  47. InstructionBuilder(
  48. IRContext* context, BasicBlock* parent_block,
  49. IRContext::Analysis preserved_analyses = IRContext::kAnalysisNone)
  50. : InstructionBuilder(context, parent_block, parent_block->end(),
  51. preserved_analyses) {}
  52. Instruction* AddNullaryOp(uint32_t type_id, spv::Op opcode) {
  53. uint32_t result_id = 0;
  54. if (type_id != 0) {
  55. result_id = GetContext()->TakeNextId();
  56. if (result_id == 0) {
  57. return nullptr;
  58. }
  59. }
  60. std::unique_ptr<Instruction> new_inst(
  61. new Instruction(GetContext(), opcode, type_id, result_id, {}));
  62. return AddInstruction(std::move(new_inst));
  63. }
  64. Instruction* AddUnaryOp(uint32_t type_id, spv::Op opcode, uint32_t operand1) {
  65. uint32_t result_id = 0;
  66. if (type_id != 0) {
  67. result_id = GetContext()->TakeNextId();
  68. if (result_id == 0) {
  69. return nullptr;
  70. }
  71. }
  72. std::unique_ptr<Instruction> newUnOp(new Instruction(
  73. GetContext(), opcode, type_id, result_id,
  74. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}}));
  75. return AddInstruction(std::move(newUnOp));
  76. }
  77. Instruction* AddBinaryOp(uint32_t type_id, spv::Op opcode, uint32_t operand1,
  78. uint32_t operand2) {
  79. uint32_t result_id = 0;
  80. if (type_id != 0) {
  81. result_id = GetContext()->TakeNextId();
  82. if (result_id == 0) {
  83. return nullptr;
  84. }
  85. }
  86. std::unique_ptr<Instruction> newBinOp(new Instruction(
  87. GetContext(), opcode, type_id,
  88. opcode == spv::Op::OpStore ? 0 : result_id,
  89. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}},
  90. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}}}));
  91. return AddInstruction(std::move(newBinOp));
  92. }
  93. Instruction* AddTernaryOp(uint32_t type_id, spv::Op opcode, uint32_t operand1,
  94. uint32_t operand2, uint32_t operand3) {
  95. uint32_t result_id = 0;
  96. if (type_id != 0) {
  97. result_id = GetContext()->TakeNextId();
  98. if (result_id == 0) {
  99. return nullptr;
  100. }
  101. }
  102. std::unique_ptr<Instruction> newTernOp(new Instruction(
  103. GetContext(), opcode, type_id, result_id,
  104. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}},
  105. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}},
  106. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand3}}}));
  107. return AddInstruction(std::move(newTernOp));
  108. }
  109. Instruction* AddQuadOp(uint32_t type_id, spv::Op opcode, uint32_t operand1,
  110. uint32_t operand2, uint32_t operand3,
  111. uint32_t operand4) {
  112. uint32_t result_id = 0;
  113. if (type_id != 0) {
  114. result_id = GetContext()->TakeNextId();
  115. if (result_id == 0) {
  116. return nullptr;
  117. }
  118. }
  119. std::unique_ptr<Instruction> newQuadOp(new Instruction(
  120. GetContext(), opcode, type_id, result_id,
  121. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}},
  122. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}},
  123. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand3}},
  124. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand4}}}));
  125. return AddInstruction(std::move(newQuadOp));
  126. }
  127. Instruction* AddIdLiteralOp(uint32_t type_id, spv::Op opcode, uint32_t id,
  128. uint32_t uliteral) {
  129. uint32_t result_id = 0;
  130. if (type_id != 0) {
  131. result_id = GetContext()->TakeNextId();
  132. if (result_id == 0) {
  133. return nullptr;
  134. }
  135. }
  136. std::unique_ptr<Instruction> newBinOp(new Instruction(
  137. GetContext(), opcode, type_id, result_id,
  138. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {id}},
  139. {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {uliteral}}}));
  140. return AddInstruction(std::move(newBinOp));
  141. }
  142. // Creates an N-ary instruction of |opcode|.
  143. // |typid| must be the id of the instruction's type.
  144. // |operands| must be a sequence of operand ids.
  145. // Use |result| for the result id if non-zero.
  146. Instruction* AddNaryOp(uint32_t type_id, spv::Op opcode,
  147. const std::vector<uint32_t>& operands,
  148. uint32_t result = 0) {
  149. std::vector<Operand> ops;
  150. for (size_t i = 0; i < operands.size(); i++) {
  151. ops.push_back({SPV_OPERAND_TYPE_ID, {operands[i]}});
  152. }
  153. // TODO(1841): Handle id overflow.
  154. std::unique_ptr<Instruction> new_inst(new Instruction(
  155. GetContext(), opcode, type_id,
  156. result != 0 ? result : GetContext()->TakeNextId(), ops));
  157. return AddInstruction(std::move(new_inst));
  158. }
  159. // Creates a new selection merge instruction.
  160. // The id |merge_id| is the merge basic block id.
  161. Instruction* AddSelectionMerge(
  162. uint32_t merge_id, uint32_t selection_control = static_cast<uint32_t>(
  163. spv::SelectionControlMask::MaskNone)) {
  164. std::unique_ptr<Instruction> new_branch_merge(new Instruction(
  165. GetContext(), spv::Op::OpSelectionMerge, 0, 0,
  166. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}},
  167. {spv_operand_type_t::SPV_OPERAND_TYPE_SELECTION_CONTROL,
  168. {selection_control}}}));
  169. return AddInstruction(std::move(new_branch_merge));
  170. }
  171. // Creates a new loop merge instruction.
  172. // The id |merge_id| is the basic block id of the merge block.
  173. // |continue_id| is the id of the continue block.
  174. // |loop_control| are the loop control flags to be added to the instruction.
  175. Instruction* AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
  176. uint32_t loop_control = static_cast<uint32_t>(
  177. spv::LoopControlMask::MaskNone)) {
  178. std::unique_ptr<Instruction> new_branch_merge(new Instruction(
  179. GetContext(), spv::Op::OpLoopMerge, 0, 0,
  180. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}},
  181. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {continue_id}},
  182. {spv_operand_type_t::SPV_OPERAND_TYPE_LOOP_CONTROL, {loop_control}}}));
  183. return AddInstruction(std::move(new_branch_merge));
  184. }
  185. // Creates a new branch instruction to |label_id|.
  186. // Note that the user must make sure the final basic block is
  187. // well formed.
  188. Instruction* AddBranch(uint32_t label_id) {
  189. std::unique_ptr<Instruction> new_branch(new Instruction(
  190. GetContext(), spv::Op::OpBranch, 0, 0,
  191. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {label_id}}}));
  192. return AddInstruction(std::move(new_branch));
  193. }
  194. // Creates a new conditional instruction and the associated selection merge
  195. // instruction if requested.
  196. // The id |cond_id| is the id of the condition instruction, must be of
  197. // type bool.
  198. // The id |true_id| is the id of the basic block to branch to if the condition
  199. // is true.
  200. // The id |false_id| is the id of the basic block to branch to if the
  201. // condition is false.
  202. // The id |merge_id| is the id of the merge basic block for the selection
  203. // merge instruction. If |merge_id| equals kInvalidId then no selection merge
  204. // instruction will be created.
  205. // The value |selection_control| is the selection control flag for the
  206. // selection merge instruction.
  207. // Note that the user must make sure the final basic block is
  208. // well formed.
  209. Instruction* AddConditionalBranch(
  210. uint32_t cond_id, uint32_t true_id, uint32_t false_id,
  211. uint32_t merge_id = kInvalidId,
  212. uint32_t selection_control =
  213. static_cast<uint32_t>(spv::SelectionControlMask::MaskNone)) {
  214. if (merge_id != kInvalidId) {
  215. AddSelectionMerge(merge_id, selection_control);
  216. }
  217. std::unique_ptr<Instruction> new_branch(new Instruction(
  218. GetContext(), spv::Op::OpBranchConditional, 0, 0,
  219. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {cond_id}},
  220. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {true_id}},
  221. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {false_id}}}));
  222. return AddInstruction(std::move(new_branch));
  223. }
  224. // Creates a new switch instruction and the associated selection merge
  225. // instruction if requested.
  226. // The id |selector_id| is the id of the selector instruction, must be of
  227. // type int.
  228. // The id |default_id| is the id of the default basic block to branch to.
  229. // The vector |targets| is the pair of literal/branch id.
  230. // The id |merge_id| is the id of the merge basic block for the selection
  231. // merge instruction. If |merge_id| equals kInvalidId then no selection merge
  232. // instruction will be created.
  233. // The value |selection_control| is the selection control flag for the
  234. // selection merge instruction.
  235. // Note that the user must make sure the final basic block is
  236. // well formed.
  237. Instruction* AddSwitch(
  238. uint32_t selector_id, uint32_t default_id,
  239. const std::vector<std::pair<Operand::OperandData, uint32_t>>& targets,
  240. uint32_t merge_id = kInvalidId,
  241. uint32_t selection_control =
  242. static_cast<uint32_t>(spv::SelectionControlMask::MaskNone)) {
  243. if (merge_id != kInvalidId) {
  244. AddSelectionMerge(merge_id, selection_control);
  245. }
  246. std::vector<Operand> operands;
  247. operands.emplace_back(
  248. Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {selector_id}});
  249. operands.emplace_back(
  250. Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {default_id}});
  251. for (auto& target : targets) {
  252. operands.emplace_back(
  253. Operand{spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
  254. target.first});
  255. operands.emplace_back(
  256. Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {target.second}});
  257. }
  258. std::unique_ptr<Instruction> new_switch(
  259. new Instruction(GetContext(), spv::Op::OpSwitch, 0, 0, operands));
  260. return AddInstruction(std::move(new_switch));
  261. }
  262. // Creates a phi instruction.
  263. // The id |type| must be the id of the phi instruction's type.
  264. // The vector |incomings| must be a sequence of pairs of <definition id,
  265. // parent id>.
  266. Instruction* AddPhi(uint32_t type, const std::vector<uint32_t>& incomings,
  267. uint32_t result = 0) {
  268. assert(incomings.size() % 2 == 0 && "A sequence of pairs is expected");
  269. return AddNaryOp(type, spv::Op::OpPhi, incomings, result);
  270. }
  271. // Creates an addition instruction.
  272. // The id |type| must be the id of the instruction's type, must be the same as
  273. // |op1| and |op2| types.
  274. // The id |op1| is the left hand side of the operation.
  275. // The id |op2| is the right hand side of the operation.
  276. Instruction* AddIAdd(uint32_t type, uint32_t op1, uint32_t op2) {
  277. // TODO(1841): Handle id overflow.
  278. std::unique_ptr<Instruction> inst(new Instruction(
  279. GetContext(), spv::Op::OpIAdd, type, GetContext()->TakeNextId(),
  280. {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}}));
  281. return AddInstruction(std::move(inst));
  282. }
  283. // Creates a less than instruction for unsigned integer.
  284. // The id |op1| is the left hand side of the operation.
  285. // The id |op2| is the right hand side of the operation.
  286. // It is assumed that |op1| and |op2| have the same underlying type.
  287. Instruction* AddULessThan(uint32_t op1, uint32_t op2) {
  288. analysis::Bool bool_type;
  289. uint32_t type = GetContext()->get_type_mgr()->GetId(&bool_type);
  290. // TODO(1841): Handle id overflow.
  291. std::unique_ptr<Instruction> inst(new Instruction(
  292. GetContext(), spv::Op::OpULessThan, type, GetContext()->TakeNextId(),
  293. {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}}));
  294. return AddInstruction(std::move(inst));
  295. }
  296. // Creates a less than instruction for signed integer.
  297. // The id |op1| is the left hand side of the operation.
  298. // The id |op2| is the right hand side of the operation.
  299. // It is assumed that |op1| and |op2| have the same underlying type.
  300. Instruction* AddSLessThan(uint32_t op1, uint32_t op2) {
  301. analysis::Bool bool_type;
  302. uint32_t type = GetContext()->get_type_mgr()->GetId(&bool_type);
  303. // TODO(1841): Handle id overflow.
  304. std::unique_ptr<Instruction> inst(new Instruction(
  305. GetContext(), spv::Op::OpSLessThan, type, GetContext()->TakeNextId(),
  306. {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}}));
  307. return AddInstruction(std::move(inst));
  308. }
  309. // Creates an OpILessThan or OpULessThen instruction depending on the sign of
  310. // |op1|. The id |op1| is the left hand side of the operation. The id |op2| is
  311. // the right hand side of the operation. It is assumed that |op1| and |op2|
  312. // have the same underlying type.
  313. Instruction* AddLessThan(uint32_t op1, uint32_t op2) {
  314. Instruction* op1_insn = context_->get_def_use_mgr()->GetDef(op1);
  315. analysis::Type* type =
  316. GetContext()->get_type_mgr()->GetType(op1_insn->type_id());
  317. analysis::Integer* int_type = type->AsInteger();
  318. assert(int_type && "Operand is not of int type");
  319. if (int_type->IsSigned())
  320. return AddSLessThan(op1, op2);
  321. else
  322. return AddULessThan(op1, op2);
  323. }
  324. // Creates a select instruction.
  325. // |type| must match the types of |true_value| and |false_value|. It is up to
  326. // the caller to ensure that |cond| is a correct type (bool or vector of
  327. // bool) for |type|.
  328. Instruction* AddSelect(uint32_t type, uint32_t cond, uint32_t true_value,
  329. uint32_t false_value) {
  330. // TODO(1841): Handle id overflow.
  331. std::unique_ptr<Instruction> select(new Instruction(
  332. GetContext(), spv::Op::OpSelect, type, GetContext()->TakeNextId(),
  333. std::initializer_list<Operand>{{SPV_OPERAND_TYPE_ID, {cond}},
  334. {SPV_OPERAND_TYPE_ID, {true_value}},
  335. {SPV_OPERAND_TYPE_ID, {false_value}}}));
  336. return AddInstruction(std::move(select));
  337. }
  338. // Returns a pointer to the definition of a signed 32-bit integer constant
  339. // with the given value. Returns |nullptr| if the constant does not exist and
  340. // cannot be created.
  341. Instruction* GetSintConstant(int32_t value) {
  342. return GetIntConstant<int32_t>(value, true);
  343. }
  344. // Create a composite construct.
  345. // |type| should be a composite type and the number of elements it has should
  346. // match the size od |ids|.
  347. Instruction* AddCompositeConstruct(uint32_t type,
  348. const std::vector<uint32_t>& ids) {
  349. std::vector<Operand> ops;
  350. for (auto id : ids) {
  351. ops.emplace_back(SPV_OPERAND_TYPE_ID,
  352. std::initializer_list<uint32_t>{id});
  353. }
  354. // TODO(1841): Handle id overflow.
  355. std::unique_ptr<Instruction> construct(
  356. new Instruction(GetContext(), spv::Op::OpCompositeConstruct, type,
  357. GetContext()->TakeNextId(), ops));
  358. return AddInstruction(std::move(construct));
  359. }
  360. // Returns a pointer to the definition of an unsigned 32-bit integer constant
  361. // with the given value. Returns |nullptr| if the constant does not exist and
  362. // cannot be created.
  363. Instruction* GetUintConstant(uint32_t value) {
  364. return GetIntConstant<uint32_t>(value, false);
  365. }
  366. uint32_t GetUintConstantId(uint32_t value) {
  367. Instruction* uint_inst = GetUintConstant(value);
  368. return (uint_inst != nullptr ? uint_inst->result_id() : 0);
  369. }
  370. // Adds either a signed or unsigned 32 bit integer constant to the binary
  371. // depending on the |sign|. If |sign| is true then the value is added as a
  372. // signed constant otherwise as an unsigned constant. If |sign| is false the
  373. // value must not be a negative number. Returns false if the constant does
  374. // not exists and could be be created.
  375. template <typename T>
  376. Instruction* GetIntConstant(T value, bool sign) {
  377. // Assert that we are not trying to store a negative number in an unsigned
  378. // type.
  379. if (!sign)
  380. assert(value >= 0 &&
  381. "Trying to add a signed integer with an unsigned type!");
  382. analysis::Integer int_type{32, sign};
  383. // Get or create the integer type. This rebuilds the type and manages the
  384. // memory for the rebuilt type.
  385. uint32_t type_id =
  386. GetContext()->get_type_mgr()->GetTypeInstruction(&int_type);
  387. if (type_id == 0) {
  388. return nullptr;
  389. }
  390. // Get the memory managed type so that it is safe to be stored by
  391. // GetConstant.
  392. analysis::Type* rebuilt_type =
  393. GetContext()->get_type_mgr()->GetType(type_id);
  394. // Even if the value is negative we need to pass the bit pattern as a
  395. // uint32_t to GetConstant.
  396. uint32_t word = value;
  397. // Create the constant value.
  398. const analysis::Constant* constant =
  399. GetContext()->get_constant_mgr()->GetConstant(rebuilt_type, {word});
  400. // Create the OpConstant instruction using the type and the value.
  401. return GetContext()->get_constant_mgr()->GetDefiningInstruction(constant);
  402. }
  403. Instruction* AddCompositeExtract(uint32_t type, uint32_t id_of_composite,
  404. const std::vector<uint32_t>& index_list) {
  405. std::vector<Operand> operands;
  406. operands.push_back({SPV_OPERAND_TYPE_ID, {id_of_composite}});
  407. for (uint32_t index : index_list) {
  408. operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {index}});
  409. }
  410. // TODO(1841): Handle id overflow.
  411. std::unique_ptr<Instruction> new_inst(
  412. new Instruction(GetContext(), spv::Op::OpCompositeExtract, type,
  413. GetContext()->TakeNextId(), operands));
  414. return AddInstruction(std::move(new_inst));
  415. }
  416. // Creates an unreachable instruction.
  417. Instruction* AddUnreachable() {
  418. std::unique_ptr<Instruction> select(
  419. new Instruction(GetContext(), spv::Op::OpUnreachable, 0, 0,
  420. std::initializer_list<Operand>{}));
  421. return AddInstruction(std::move(select));
  422. }
  423. Instruction* AddAccessChain(uint32_t type_id, uint32_t base_ptr_id,
  424. std::vector<uint32_t> ids) {
  425. std::vector<Operand> operands;
  426. operands.push_back({SPV_OPERAND_TYPE_ID, {base_ptr_id}});
  427. for (uint32_t index_id : ids) {
  428. operands.push_back({SPV_OPERAND_TYPE_ID, {index_id}});
  429. }
  430. // TODO(1841): Handle id overflow.
  431. std::unique_ptr<Instruction> new_inst(
  432. new Instruction(GetContext(), spv::Op::OpAccessChain, type_id,
  433. GetContext()->TakeNextId(), operands));
  434. return AddInstruction(std::move(new_inst));
  435. }
  436. Instruction* AddLoad(uint32_t type_id, uint32_t base_ptr_id) {
  437. std::vector<Operand> operands;
  438. operands.push_back({SPV_OPERAND_TYPE_ID, {base_ptr_id}});
  439. // TODO(1841): Handle id overflow.
  440. std::unique_ptr<Instruction> new_inst(
  441. new Instruction(GetContext(), spv::Op::OpLoad, type_id,
  442. GetContext()->TakeNextId(), operands));
  443. return AddInstruction(std::move(new_inst));
  444. }
  445. Instruction* AddVariable(uint32_t type_id, uint32_t storage_class) {
  446. std::vector<Operand> operands;
  447. operands.push_back({SPV_OPERAND_TYPE_ID, {storage_class}});
  448. std::unique_ptr<Instruction> new_inst(
  449. new Instruction(GetContext(), spv::Op::OpVariable, type_id,
  450. GetContext()->TakeNextId(), operands));
  451. return AddInstruction(std::move(new_inst));
  452. }
  453. Instruction* AddStore(uint32_t ptr_id, uint32_t obj_id) {
  454. std::vector<Operand> operands;
  455. operands.push_back({SPV_OPERAND_TYPE_ID, {ptr_id}});
  456. operands.push_back({SPV_OPERAND_TYPE_ID, {obj_id}});
  457. std::unique_ptr<Instruction> new_inst(
  458. new Instruction(GetContext(), spv::Op::OpStore, 0, 0, operands));
  459. return AddInstruction(std::move(new_inst));
  460. }
  461. Instruction* AddFunctionCall(uint32_t result_type, uint32_t function,
  462. const std::vector<uint32_t>& parameters) {
  463. std::vector<Operand> operands;
  464. operands.push_back({SPV_OPERAND_TYPE_ID, {function}});
  465. for (uint32_t id : parameters) {
  466. operands.push_back({SPV_OPERAND_TYPE_ID, {id}});
  467. }
  468. uint32_t result_id = GetContext()->TakeNextId();
  469. if (result_id == 0) {
  470. return nullptr;
  471. }
  472. std::unique_ptr<Instruction> new_inst(
  473. new Instruction(GetContext(), spv::Op::OpFunctionCall, result_type,
  474. result_id, operands));
  475. return AddInstruction(std::move(new_inst));
  476. }
  477. Instruction* AddVectorShuffle(uint32_t result_type, uint32_t vec1,
  478. uint32_t vec2,
  479. const std::vector<uint32_t>& components) {
  480. std::vector<Operand> operands;
  481. operands.push_back({SPV_OPERAND_TYPE_ID, {vec1}});
  482. operands.push_back({SPV_OPERAND_TYPE_ID, {vec2}});
  483. for (uint32_t id : components) {
  484. operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {id}});
  485. }
  486. uint32_t result_id = GetContext()->TakeNextId();
  487. if (result_id == 0) {
  488. return nullptr;
  489. }
  490. std::unique_ptr<Instruction> new_inst(
  491. new Instruction(GetContext(), spv::Op::OpVectorShuffle, result_type,
  492. result_id, operands));
  493. return AddInstruction(std::move(new_inst));
  494. }
  495. Instruction* AddNaryExtendedInstruction(
  496. uint32_t result_type, uint32_t set, uint32_t instruction,
  497. const std::vector<uint32_t>& ext_operands) {
  498. std::vector<Operand> operands;
  499. operands.push_back({SPV_OPERAND_TYPE_ID, {set}});
  500. operands.push_back(
  501. {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, {instruction}});
  502. for (uint32_t id : ext_operands) {
  503. operands.push_back({SPV_OPERAND_TYPE_ID, {id}});
  504. }
  505. uint32_t result_id = GetContext()->TakeNextId();
  506. if (result_id == 0) {
  507. return nullptr;
  508. }
  509. std::unique_ptr<Instruction> new_inst(new Instruction(
  510. GetContext(), spv::Op::OpExtInst, result_type, result_id, operands));
  511. return AddInstruction(std::move(new_inst));
  512. }
  513. // Inserts the new instruction before the insertion point.
  514. Instruction* AddInstruction(std::unique_ptr<Instruction>&& insn) {
  515. Instruction* insn_ptr = &*insert_before_.InsertBefore(std::move(insn));
  516. UpdateInstrToBlockMapping(insn_ptr);
  517. UpdateDefUseMgr(insn_ptr);
  518. return insn_ptr;
  519. }
  520. // Returns the insertion point iterator.
  521. InsertionPointTy GetInsertPoint() { return insert_before_; }
  522. // Change the insertion point to insert before the instruction
  523. // |insert_before|.
  524. void SetInsertPoint(Instruction* insert_before) {
  525. parent_ = context_->get_instr_block(insert_before);
  526. insert_before_ = InsertionPointTy(insert_before);
  527. }
  528. // Change the insertion point to insert at the end of the basic block
  529. // |parent_block|.
  530. void SetInsertPoint(BasicBlock* parent_block) {
  531. parent_ = parent_block;
  532. insert_before_ = parent_block->end();
  533. }
  534. // Returns the context which instructions are constructed for.
  535. IRContext* GetContext() const { return context_; }
  536. // Returns the set of preserved analyses.
  537. inline IRContext::Analysis GetPreservedAnalysis() const {
  538. return preserved_analyses_;
  539. }
  540. private:
  541. InstructionBuilder(IRContext* context, BasicBlock* parent,
  542. InsertionPointTy insert_before,
  543. IRContext::Analysis preserved_analyses)
  544. : context_(context),
  545. parent_(parent),
  546. insert_before_(insert_before),
  547. preserved_analyses_(preserved_analyses) {
  548. assert(!(preserved_analyses_ & ~(IRContext::kAnalysisDefUse |
  549. IRContext::kAnalysisInstrToBlockMapping)));
  550. }
  551. // Returns true if the users requested to update |analysis|.
  552. inline bool IsAnalysisUpdateRequested(IRContext::Analysis analysis) const {
  553. if (!GetContext()->AreAnalysesValid(analysis)) {
  554. // Do not try to update something that is not built.
  555. return false;
  556. }
  557. return preserved_analyses_ & analysis;
  558. }
  559. // Updates the def/use manager if the user requested it. If an update was not
  560. // requested, this function does nothing.
  561. inline void UpdateDefUseMgr(Instruction* insn) {
  562. if (IsAnalysisUpdateRequested(IRContext::kAnalysisDefUse))
  563. GetContext()->get_def_use_mgr()->AnalyzeInstDefUse(insn);
  564. }
  565. // Updates the instruction to block analysis if the user requested it. If
  566. // an update was not requested, this function does nothing.
  567. inline void UpdateInstrToBlockMapping(Instruction* insn) {
  568. if (IsAnalysisUpdateRequested(IRContext::kAnalysisInstrToBlockMapping) &&
  569. parent_)
  570. GetContext()->set_instr_block(insn, parent_);
  571. }
  572. IRContext* context_;
  573. BasicBlock* parent_;
  574. InsertionPointTy insert_before_;
  575. const IRContext::Analysis preserved_analyses_;
  576. };
  577. } // namespace opt
  578. } // namespace spvtools
  579. #endif // SOURCE_OPT_IR_BUILDER_H_