• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 const 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,SpvOp opcode)61   Instruction* AddNullaryOp(uint32_t type_id, SpvOp 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,SpvOp opcode,uint32_t operand1)74   Instruction* AddUnaryOp(uint32_t type_id, SpvOp 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,SpvOp opcode,uint32_t operand1,uint32_t operand2)88   Instruction* AddBinaryOp(uint32_t type_id, SpvOp 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, opcode == SpvOpStore ? 0 : result_id,
99         {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}},
100          {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}}}));
101     return AddInstruction(std::move(newBinOp));
102   }
103 
AddTernaryOp(uint32_t type_id,SpvOp opcode,uint32_t operand1,uint32_t operand2,uint32_t operand3)104   Instruction* AddTernaryOp(uint32_t type_id, SpvOp opcode, uint32_t operand1,
105                             uint32_t operand2, uint32_t operand3) {
106     uint32_t result_id = 0;
107     if (type_id != 0) {
108       result_id = GetContext()->TakeNextId();
109       if (result_id == 0) {
110         return nullptr;
111       }
112     }
113     std::unique_ptr<Instruction> newTernOp(new Instruction(
114         GetContext(), opcode, type_id, result_id,
115         {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}},
116          {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}},
117          {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand3}}}));
118     return AddInstruction(std::move(newTernOp));
119   }
120 
AddQuadOp(uint32_t type_id,SpvOp opcode,uint32_t operand1,uint32_t operand2,uint32_t operand3,uint32_t operand4)121   Instruction* AddQuadOp(uint32_t type_id, SpvOp opcode, uint32_t operand1,
122                          uint32_t operand2, uint32_t operand3,
123                          uint32_t operand4) {
124     uint32_t result_id = 0;
125     if (type_id != 0) {
126       result_id = GetContext()->TakeNextId();
127       if (result_id == 0) {
128         return nullptr;
129       }
130     }
131     std::unique_ptr<Instruction> newQuadOp(new Instruction(
132         GetContext(), opcode, type_id, result_id,
133         {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}},
134          {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}},
135          {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand3}},
136          {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand4}}}));
137     return AddInstruction(std::move(newQuadOp));
138   }
139 
AddIdLiteralOp(uint32_t type_id,SpvOp opcode,uint32_t id,uint32_t uliteral)140   Instruction* AddIdLiteralOp(uint32_t type_id, SpvOp opcode, uint32_t id,
141                               uint32_t uliteral) {
142     uint32_t result_id = 0;
143     if (type_id != 0) {
144       result_id = GetContext()->TakeNextId();
145       if (result_id == 0) {
146         return nullptr;
147       }
148     }
149     std::unique_ptr<Instruction> newBinOp(new Instruction(
150         GetContext(), opcode, type_id, result_id,
151         {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {id}},
152          {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {uliteral}}}));
153     return AddInstruction(std::move(newBinOp));
154   }
155 
156   // Creates an N-ary instruction of |opcode|.
157   // |typid| must be the id of the instruction's type.
158   // |operands| must be a sequence of operand ids.
159   // Use |result| for the result id if non-zero.
160   Instruction* AddNaryOp(uint32_t type_id, SpvOp opcode,
161                          const std::vector<uint32_t>& operands,
162                          uint32_t result = 0) {
163     std::vector<Operand> ops;
164     for (size_t i = 0; i < operands.size(); i++) {
165       ops.push_back({SPV_OPERAND_TYPE_ID, {operands[i]}});
166     }
167     // TODO(1841): Handle id overflow.
168     std::unique_ptr<Instruction> new_inst(new Instruction(
169         GetContext(), opcode, type_id,
170         result != 0 ? result : GetContext()->TakeNextId(), ops));
171     return AddInstruction(std::move(new_inst));
172   }
173 
174   // Creates a new selection merge instruction.
175   // The id |merge_id| is the merge basic block id.
176   Instruction* AddSelectionMerge(
177       uint32_t merge_id,
178       uint32_t selection_control = SpvSelectionControlMaskNone) {
179     std::unique_ptr<Instruction> new_branch_merge(new Instruction(
180         GetContext(), SpvOpSelectionMerge, 0, 0,
181         {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}},
182          {spv_operand_type_t::SPV_OPERAND_TYPE_SELECTION_CONTROL,
183           {selection_control}}}));
184     return AddInstruction(std::move(new_branch_merge));
185   }
186 
187   // Creates a new loop merge instruction.
188   // The id |merge_id| is the basic block id of the merge block.
189   // |continue_id| is the id of the continue block.
190   // |loop_control| are the loop control flags to be added to the instruction.
191   Instruction* AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
192                             uint32_t loop_control = SpvLoopControlMaskNone) {
193     std::unique_ptr<Instruction> new_branch_merge(new Instruction(
194         GetContext(), SpvOpLoopMerge, 0, 0,
195         {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}},
196          {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {continue_id}},
197          {spv_operand_type_t::SPV_OPERAND_TYPE_LOOP_CONTROL, {loop_control}}}));
198     return AddInstruction(std::move(new_branch_merge));
199   }
200 
201   // Creates a new branch instruction to |label_id|.
202   // Note that the user must make sure the final basic block is
203   // well formed.
AddBranch(uint32_t label_id)204   Instruction* AddBranch(uint32_t label_id) {
205     std::unique_ptr<Instruction> new_branch(new Instruction(
206         GetContext(), SpvOpBranch, 0, 0,
207         {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {label_id}}}));
208     return AddInstruction(std::move(new_branch));
209   }
210 
211   // Creates a new conditional instruction and the associated selection merge
212   // instruction if requested.
213   // The id |cond_id| is the id of the condition instruction, must be of
214   // type bool.
215   // The id |true_id| is the id of the basic block to branch to if the condition
216   // is true.
217   // The id |false_id| is the id of the basic block to branch to if the
218   // condition is false.
219   // The id |merge_id| is the id of the merge basic block for the selection
220   // merge instruction. If |merge_id| equals kInvalidId then no selection merge
221   // instruction will be created.
222   // The value |selection_control| is the selection control flag for the
223   // selection merge instruction.
224   // Note that the user must make sure the final basic block is
225   // well formed.
226   Instruction* AddConditionalBranch(
227       uint32_t cond_id, uint32_t true_id, uint32_t false_id,
228       uint32_t merge_id = kInvalidId,
229       uint32_t selection_control = SpvSelectionControlMaskNone) {
230     if (merge_id != kInvalidId) {
231       AddSelectionMerge(merge_id, selection_control);
232     }
233     std::unique_ptr<Instruction> new_branch(new Instruction(
234         GetContext(), SpvOpBranchConditional, 0, 0,
235         {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {cond_id}},
236          {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {true_id}},
237          {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {false_id}}}));
238     return AddInstruction(std::move(new_branch));
239   }
240 
241   // Creates a new switch instruction and the associated selection merge
242   // instruction if requested.
243   // The id |selector_id| is the id of the selector instruction, must be of
244   // type int.
245   // The id |default_id| is the id of the default basic block to branch to.
246   // The vector |targets| is the pair of literal/branch id.
247   // The id |merge_id| is the id of the merge basic block for the selection
248   // merge instruction. If |merge_id| equals kInvalidId then no selection merge
249   // instruction will be created.
250   // The value |selection_control| is the selection control flag for the
251   // selection merge instruction.
252   // Note that the user must make sure the final basic block is
253   // well formed.
254   Instruction* AddSwitch(
255       uint32_t selector_id, uint32_t default_id,
256       const std::vector<std::pair<Operand::OperandData, uint32_t>>& targets,
257       uint32_t merge_id = kInvalidId,
258       uint32_t selection_control = SpvSelectionControlMaskNone) {
259     if (merge_id != kInvalidId) {
260       AddSelectionMerge(merge_id, selection_control);
261     }
262     std::vector<Operand> operands;
263     operands.emplace_back(
264         Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {selector_id}});
265     operands.emplace_back(
266         Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {default_id}});
267     for (auto& target : targets) {
268       operands.emplace_back(
269           Operand{spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
270                   target.first});
271       operands.emplace_back(
272           Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {target.second}});
273     }
274     std::unique_ptr<Instruction> new_switch(
275         new Instruction(GetContext(), SpvOpSwitch, 0, 0, operands));
276     return AddInstruction(std::move(new_switch));
277   }
278 
279   // Creates a phi instruction.
280   // The id |type| must be the id of the phi instruction's type.
281   // The vector |incomings| must be a sequence of pairs of <definition id,
282   // parent id>.
283   Instruction* AddPhi(uint32_t type, const std::vector<uint32_t>& incomings,
284                       uint32_t result = 0) {
285     assert(incomings.size() % 2 == 0 && "A sequence of pairs is expected");
286     return AddNaryOp(type, SpvOpPhi, incomings, result);
287   }
288 
289   // Creates an addition instruction.
290   // The id |type| must be the id of the instruction's type, must be the same as
291   // |op1| and |op2| types.
292   // The id |op1| is the left hand side of the operation.
293   // The id |op2| is the right hand side of the operation.
AddIAdd(uint32_t type,uint32_t op1,uint32_t op2)294   Instruction* AddIAdd(uint32_t type, uint32_t op1, uint32_t op2) {
295     // TODO(1841): Handle id overflow.
296     std::unique_ptr<Instruction> inst(new Instruction(
297         GetContext(), SpvOpIAdd, type, GetContext()->TakeNextId(),
298         {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}}));
299     return AddInstruction(std::move(inst));
300   }
301 
302   // Creates a less than instruction for unsigned integer.
303   // The id |op1| is the left hand side of the operation.
304   // The id |op2| is the right hand side of the operation.
305   // It is assumed that |op1| and |op2| have the same underlying type.
AddULessThan(uint32_t op1,uint32_t op2)306   Instruction* AddULessThan(uint32_t op1, uint32_t op2) {
307     analysis::Bool bool_type;
308     uint32_t type = GetContext()->get_type_mgr()->GetId(&bool_type);
309     // TODO(1841): Handle id overflow.
310     std::unique_ptr<Instruction> inst(new Instruction(
311         GetContext(), SpvOpULessThan, type, GetContext()->TakeNextId(),
312         {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}}));
313     return AddInstruction(std::move(inst));
314   }
315 
316   // Creates a less than instruction for signed integer.
317   // The id |op1| is the left hand side of the operation.
318   // The id |op2| is the right hand side of the operation.
319   // It is assumed that |op1| and |op2| have the same underlying type.
AddSLessThan(uint32_t op1,uint32_t op2)320   Instruction* AddSLessThan(uint32_t op1, uint32_t op2) {
321     analysis::Bool bool_type;
322     uint32_t type = GetContext()->get_type_mgr()->GetId(&bool_type);
323     // TODO(1841): Handle id overflow.
324     std::unique_ptr<Instruction> inst(new Instruction(
325         GetContext(), SpvOpSLessThan, type, GetContext()->TakeNextId(),
326         {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}}));
327     return AddInstruction(std::move(inst));
328   }
329 
330   // Creates an OpILessThan or OpULessThen instruction depending on the sign of
331   // |op1|. The id |op1| is the left hand side of the operation. The id |op2| is
332   // the right hand side of the operation. It is assumed that |op1| and |op2|
333   // have the same underlying type.
AddLessThan(uint32_t op1,uint32_t op2)334   Instruction* AddLessThan(uint32_t op1, uint32_t op2) {
335     Instruction* op1_insn = context_->get_def_use_mgr()->GetDef(op1);
336     analysis::Type* type =
337         GetContext()->get_type_mgr()->GetType(op1_insn->type_id());
338     analysis::Integer* int_type = type->AsInteger();
339     assert(int_type && "Operand is not of int type");
340 
341     if (int_type->IsSigned())
342       return AddSLessThan(op1, op2);
343     else
344       return AddULessThan(op1, op2);
345   }
346 
347   // Creates a select instruction.
348   // |type| must match the types of |true_value| and |false_value|. It is up to
349   // the caller to ensure that |cond| is a correct type (bool or vector of
350   // bool) for |type|.
AddSelect(uint32_t type,uint32_t cond,uint32_t true_value,uint32_t false_value)351   Instruction* AddSelect(uint32_t type, uint32_t cond, uint32_t true_value,
352                          uint32_t false_value) {
353     // TODO(1841): Handle id overflow.
354     std::unique_ptr<Instruction> select(new Instruction(
355         GetContext(), SpvOpSelect, type, GetContext()->TakeNextId(),
356         std::initializer_list<Operand>{{SPV_OPERAND_TYPE_ID, {cond}},
357                                        {SPV_OPERAND_TYPE_ID, {true_value}},
358                                        {SPV_OPERAND_TYPE_ID, {false_value}}}));
359     return AddInstruction(std::move(select));
360   }
361 
362   // Adds a signed int32 constant to the binary.
363   // The |value| parameter is the constant value to be added.
GetSintConstant(int32_t value)364   Instruction* GetSintConstant(int32_t value) {
365     return GetIntConstant<int32_t>(value, true);
366   }
367 
368   // Create a composite construct.
369   // |type| should be a composite type and the number of elements it has should
370   // match the size od |ids|.
AddCompositeConstruct(uint32_t type,const std::vector<uint32_t> & ids)371   Instruction* AddCompositeConstruct(uint32_t type,
372                                      const std::vector<uint32_t>& ids) {
373     std::vector<Operand> ops;
374     for (auto id : ids) {
375       ops.emplace_back(SPV_OPERAND_TYPE_ID,
376                        std::initializer_list<uint32_t>{id});
377     }
378     // TODO(1841): Handle id overflow.
379     std::unique_ptr<Instruction> construct(
380         new Instruction(GetContext(), SpvOpCompositeConstruct, type,
381                         GetContext()->TakeNextId(), ops));
382     return AddInstruction(std::move(construct));
383   }
384   // Adds an unsigned int32 constant to the binary.
385   // The |value| parameter is the constant value to be added.
GetUintConstant(uint32_t value)386   Instruction* GetUintConstant(uint32_t value) {
387     return GetIntConstant<uint32_t>(value, false);
388   }
389 
GetUintConstantId(uint32_t value)390   uint32_t GetUintConstantId(uint32_t value) {
391     Instruction* uint_inst = GetUintConstant(value);
392     return uint_inst->result_id();
393   }
394 
395   // Adds either a signed or unsigned 32 bit integer constant to the binary
396   // depedning on the |sign|. If |sign| is true then the value is added as a
397   // signed constant otherwise as an unsigned constant. If |sign| is false the
398   // value must not be a negative number.
399   template <typename T>
GetIntConstant(T value,bool sign)400   Instruction* GetIntConstant(T value, bool sign) {
401     // Assert that we are not trying to store a negative number in an unsigned
402     // type.
403     if (!sign)
404       assert(value >= 0 &&
405              "Trying to add a signed integer with an unsigned type!");
406 
407     analysis::Integer int_type{32, sign};
408 
409     // Get or create the integer type. This rebuilds the type and manages the
410     // memory for the rebuilt type.
411     uint32_t type_id =
412         GetContext()->get_type_mgr()->GetTypeInstruction(&int_type);
413 
414     // Get the memory managed type so that it is safe to be stored by
415     // GetConstant.
416     analysis::Type* rebuilt_type =
417         GetContext()->get_type_mgr()->GetType(type_id);
418 
419     // Even if the value is negative we need to pass the bit pattern as a
420     // uint32_t to GetConstant.
421     uint32_t word = value;
422 
423     // Create the constant value.
424     const analysis::Constant* constant =
425         GetContext()->get_constant_mgr()->GetConstant(rebuilt_type, {word});
426 
427     // Create the OpConstant instruction using the type and the value.
428     return GetContext()->get_constant_mgr()->GetDefiningInstruction(constant);
429   }
430 
AddCompositeExtract(uint32_t type,uint32_t id_of_composite,const std::vector<uint32_t> & index_list)431   Instruction* AddCompositeExtract(uint32_t type, uint32_t id_of_composite,
432                                    const std::vector<uint32_t>& index_list) {
433     std::vector<Operand> operands;
434     operands.push_back({SPV_OPERAND_TYPE_ID, {id_of_composite}});
435 
436     for (uint32_t index : index_list) {
437       operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {index}});
438     }
439 
440     // TODO(1841): Handle id overflow.
441     std::unique_ptr<Instruction> new_inst(
442         new Instruction(GetContext(), SpvOpCompositeExtract, type,
443                         GetContext()->TakeNextId(), operands));
444     return AddInstruction(std::move(new_inst));
445   }
446 
447   // Creates an unreachable instruction.
AddUnreachable()448   Instruction* AddUnreachable() {
449     std::unique_ptr<Instruction> select(
450         new Instruction(GetContext(), SpvOpUnreachable, 0, 0,
451                         std::initializer_list<Operand>{}));
452     return AddInstruction(std::move(select));
453   }
454 
AddAccessChain(uint32_t type_id,uint32_t base_ptr_id,std::vector<uint32_t> ids)455   Instruction* AddAccessChain(uint32_t type_id, uint32_t base_ptr_id,
456                               std::vector<uint32_t> ids) {
457     std::vector<Operand> operands;
458     operands.push_back({SPV_OPERAND_TYPE_ID, {base_ptr_id}});
459 
460     for (uint32_t index_id : ids) {
461       operands.push_back({SPV_OPERAND_TYPE_ID, {index_id}});
462     }
463 
464     // TODO(1841): Handle id overflow.
465     std::unique_ptr<Instruction> new_inst(
466         new Instruction(GetContext(), SpvOpAccessChain, type_id,
467                         GetContext()->TakeNextId(), operands));
468     return AddInstruction(std::move(new_inst));
469   }
470 
AddLoad(uint32_t type_id,uint32_t base_ptr_id)471   Instruction* AddLoad(uint32_t type_id, uint32_t base_ptr_id) {
472     std::vector<Operand> operands;
473     operands.push_back({SPV_OPERAND_TYPE_ID, {base_ptr_id}});
474 
475     // TODO(1841): Handle id overflow.
476     std::unique_ptr<Instruction> new_inst(
477         new Instruction(GetContext(), SpvOpLoad, type_id,
478                         GetContext()->TakeNextId(), operands));
479     return AddInstruction(std::move(new_inst));
480   }
481 
AddStore(uint32_t ptr_id,uint32_t obj_id)482   Instruction* AddStore(uint32_t ptr_id, uint32_t obj_id) {
483     std::vector<Operand> operands;
484     operands.push_back({SPV_OPERAND_TYPE_ID, {ptr_id}});
485     operands.push_back({SPV_OPERAND_TYPE_ID, {obj_id}});
486 
487     std::unique_ptr<Instruction> new_inst(
488         new Instruction(GetContext(), SpvOpStore, 0, 0, operands));
489     return AddInstruction(std::move(new_inst));
490   }
491 
AddFunctionCall(uint32_t result_type,uint32_t function,const std::vector<uint32_t> & parameters)492   Instruction* AddFunctionCall(uint32_t result_type, uint32_t function,
493                                const std::vector<uint32_t>& parameters) {
494     std::vector<Operand> operands;
495     operands.push_back({SPV_OPERAND_TYPE_ID, {function}});
496     for (uint32_t id : parameters) {
497       operands.push_back({SPV_OPERAND_TYPE_ID, {id}});
498     }
499 
500     uint32_t result_id = GetContext()->TakeNextId();
501     if (result_id == 0) {
502       return nullptr;
503     }
504     std::unique_ptr<Instruction> new_inst(new Instruction(
505         GetContext(), SpvOpFunctionCall, result_type, result_id, operands));
506     return AddInstruction(std::move(new_inst));
507   }
508 
AddVectorShuffle(uint32_t result_type,uint32_t vec1,uint32_t vec2,const std::vector<uint32_t> & components)509   Instruction* AddVectorShuffle(uint32_t result_type, uint32_t vec1,
510                                 uint32_t vec2,
511                                 const std::vector<uint32_t>& components) {
512     std::vector<Operand> operands;
513     operands.push_back({SPV_OPERAND_TYPE_ID, {vec1}});
514     operands.push_back({SPV_OPERAND_TYPE_ID, {vec2}});
515     for (uint32_t id : components) {
516       operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {id}});
517     }
518 
519     uint32_t result_id = GetContext()->TakeNextId();
520     if (result_id == 0) {
521       return nullptr;
522     }
523 
524     std::unique_ptr<Instruction> new_inst(new Instruction(
525         GetContext(), SpvOpVectorShuffle, result_type, result_id, operands));
526     return AddInstruction(std::move(new_inst));
527   }
528 
AddNaryExtendedInstruction(uint32_t result_type,uint32_t set,uint32_t instruction,const std::vector<uint32_t> & ext_operands)529   Instruction* AddNaryExtendedInstruction(
530       uint32_t result_type, uint32_t set, uint32_t instruction,
531       const std::vector<uint32_t>& ext_operands) {
532     std::vector<Operand> operands;
533     operands.push_back({SPV_OPERAND_TYPE_ID, {set}});
534     operands.push_back(
535         {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, {instruction}});
536     for (uint32_t id : ext_operands) {
537       operands.push_back({SPV_OPERAND_TYPE_ID, {id}});
538     }
539 
540     uint32_t result_id = GetContext()->TakeNextId();
541     if (result_id == 0) {
542       return nullptr;
543     }
544 
545     std::unique_ptr<Instruction> new_inst(new Instruction(
546         GetContext(), SpvOpExtInst, result_type, result_id, operands));
547     return AddInstruction(std::move(new_inst));
548   }
549 
550   // Inserts the new instruction before the insertion point.
AddInstruction(std::unique_ptr<Instruction> && insn)551   Instruction* AddInstruction(std::unique_ptr<Instruction>&& insn) {
552     Instruction* insn_ptr = &*insert_before_.InsertBefore(std::move(insn));
553     UpdateInstrToBlockMapping(insn_ptr);
554     UpdateDefUseMgr(insn_ptr);
555     return insn_ptr;
556   }
557 
558   // Returns the insertion point iterator.
GetInsertPoint()559   InsertionPointTy GetInsertPoint() { return insert_before_; }
560 
561   // Change the insertion point to insert before the instruction
562   // |insert_before|.
SetInsertPoint(Instruction * insert_before)563   void SetInsertPoint(Instruction* insert_before) {
564     parent_ = context_->get_instr_block(insert_before);
565     insert_before_ = InsertionPointTy(insert_before);
566   }
567 
568   // Change the insertion point to insert at the end of the basic block
569   // |parent_block|.
SetInsertPoint(BasicBlock * parent_block)570   void SetInsertPoint(BasicBlock* parent_block) {
571     parent_ = parent_block;
572     insert_before_ = parent_block->end();
573   }
574 
575   // Returns the context which instructions are constructed for.
GetContext()576   IRContext* GetContext() const { return context_; }
577 
578   // Returns the set of preserved analyses.
GetPreservedAnalysis()579   inline IRContext::Analysis GetPreservedAnalysis() const {
580     return preserved_analyses_;
581   }
582 
583  private:
InstructionBuilder(IRContext * context,BasicBlock * parent,InsertionPointTy insert_before,IRContext::Analysis preserved_analyses)584   InstructionBuilder(IRContext* context, BasicBlock* parent,
585                      InsertionPointTy insert_before,
586                      IRContext::Analysis preserved_analyses)
587       : context_(context),
588         parent_(parent),
589         insert_before_(insert_before),
590         preserved_analyses_(preserved_analyses) {
591     assert(!(preserved_analyses_ & ~(IRContext::kAnalysisDefUse |
592                                      IRContext::kAnalysisInstrToBlockMapping)));
593   }
594 
595   // Returns true if the users requested to update |analysis|.
IsAnalysisUpdateRequested(IRContext::Analysis analysis)596   inline bool IsAnalysisUpdateRequested(IRContext::Analysis analysis) const {
597     if (!GetContext()->AreAnalysesValid(analysis)) {
598       // Do not try to update something that is not built.
599       return false;
600     }
601     return preserved_analyses_ & analysis;
602   }
603 
604   // Updates the def/use manager if the user requested it. If an update was not
605   // requested, this function does nothing.
UpdateDefUseMgr(Instruction * insn)606   inline void UpdateDefUseMgr(Instruction* insn) {
607     if (IsAnalysisUpdateRequested(IRContext::kAnalysisDefUse))
608       GetContext()->get_def_use_mgr()->AnalyzeInstDefUse(insn);
609   }
610 
611   // Updates the instruction to block analysis if the user requested it. If
612   // an update was not requested, this function does nothing.
UpdateInstrToBlockMapping(Instruction * insn)613   inline void UpdateInstrToBlockMapping(Instruction* insn) {
614     if (IsAnalysisUpdateRequested(IRContext::kAnalysisInstrToBlockMapping) &&
615         parent_)
616       GetContext()->set_instr_block(insn, parent_);
617   }
618 
619   IRContext* context_;
620   BasicBlock* parent_;
621   InsertionPointTy insert_before_;
622   const IRContext::Analysis preserved_analyses_;
623 };
624 
625 }  // namespace opt
626 }  // namespace spvtools
627 
628 #endif  // SOURCE_OPT_IR_BUILDER_H_
629