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