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