ir_builder.h 29 KB

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