• 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   // Returns a pointer to the definition of a signed 32-bit integer constant
363   // with the given value. Returns |nullptr| if the constant does not exist and
364   // cannot be created.
GetSintConstant(int32_t value)365   Instruction* GetSintConstant(int32_t value) {
366     return GetIntConstant<int32_t>(value, true);
367   }
368 
369   // Create a composite construct.
370   // |type| should be a composite type and the number of elements it has should
371   // match the size od |ids|.
AddCompositeConstruct(uint32_t type,const std::vector<uint32_t> & ids)372   Instruction* AddCompositeConstruct(uint32_t type,
373                                      const std::vector<uint32_t>& ids) {
374     std::vector<Operand> ops;
375     for (auto id : ids) {
376       ops.emplace_back(SPV_OPERAND_TYPE_ID,
377                        std::initializer_list<uint32_t>{id});
378     }
379     // TODO(1841): Handle id overflow.
380     std::unique_ptr<Instruction> construct(
381         new Instruction(GetContext(), SpvOpCompositeConstruct, type,
382                         GetContext()->TakeNextId(), ops));
383     return AddInstruction(std::move(construct));
384   }
385 
386   // Returns a pointer to the definition of an unsigned 32-bit integer constant
387   // with the given value. Returns |nullptr| if the constant does not exist and
388   // cannot be created.
GetUintConstant(uint32_t value)389   Instruction* GetUintConstant(uint32_t value) {
390     return GetIntConstant<uint32_t>(value, false);
391   }
392 
GetUintConstantId(uint32_t value)393   uint32_t GetUintConstantId(uint32_t value) {
394     Instruction* uint_inst = GetUintConstant(value);
395     return (uint_inst != nullptr ? uint_inst->result_id() : 0);
396   }
397 
398   // Adds either a signed or unsigned 32 bit integer constant to the binary
399   // depending on the |sign|. If |sign| is true then the value is added as a
400   // signed constant otherwise as an unsigned constant. If |sign| is false the
401   // value must not be a negative number.  Returns false if the constant does
402   // not exists and could be be created.
403   template <typename T>
GetIntConstant(T value,bool sign)404   Instruction* GetIntConstant(T value, bool sign) {
405     // Assert that we are not trying to store a negative number in an unsigned
406     // type.
407     if (!sign)
408       assert(value >= 0 &&
409              "Trying to add a signed integer with an unsigned type!");
410 
411     analysis::Integer int_type{32, sign};
412 
413     // Get or create the integer type. This rebuilds the type and manages the
414     // memory for the rebuilt type.
415     uint32_t type_id =
416         GetContext()->get_type_mgr()->GetTypeInstruction(&int_type);
417 
418     if (type_id == 0) {
419       return nullptr;
420     }
421 
422     // Get the memory managed type so that it is safe to be stored by
423     // GetConstant.
424     analysis::Type* rebuilt_type =
425         GetContext()->get_type_mgr()->GetType(type_id);
426 
427     // Even if the value is negative we need to pass the bit pattern as a
428     // uint32_t to GetConstant.
429     uint32_t word = value;
430 
431     // Create the constant value.
432     const analysis::Constant* constant =
433         GetContext()->get_constant_mgr()->GetConstant(rebuilt_type, {word});
434 
435     // Create the OpConstant instruction using the type and the value.
436     return GetContext()->get_constant_mgr()->GetDefiningInstruction(constant);
437   }
438 
AddCompositeExtract(uint32_t type,uint32_t id_of_composite,const std::vector<uint32_t> & index_list)439   Instruction* AddCompositeExtract(uint32_t type, uint32_t id_of_composite,
440                                    const std::vector<uint32_t>& index_list) {
441     std::vector<Operand> operands;
442     operands.push_back({SPV_OPERAND_TYPE_ID, {id_of_composite}});
443 
444     for (uint32_t index : index_list) {
445       operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {index}});
446     }
447 
448     // TODO(1841): Handle id overflow.
449     std::unique_ptr<Instruction> new_inst(
450         new Instruction(GetContext(), SpvOpCompositeExtract, type,
451                         GetContext()->TakeNextId(), operands));
452     return AddInstruction(std::move(new_inst));
453   }
454 
455   // Creates an unreachable instruction.
AddUnreachable()456   Instruction* AddUnreachable() {
457     std::unique_ptr<Instruction> select(
458         new Instruction(GetContext(), SpvOpUnreachable, 0, 0,
459                         std::initializer_list<Operand>{}));
460     return AddInstruction(std::move(select));
461   }
462 
AddAccessChain(uint32_t type_id,uint32_t base_ptr_id,std::vector<uint32_t> ids)463   Instruction* AddAccessChain(uint32_t type_id, uint32_t base_ptr_id,
464                               std::vector<uint32_t> ids) {
465     std::vector<Operand> operands;
466     operands.push_back({SPV_OPERAND_TYPE_ID, {base_ptr_id}});
467 
468     for (uint32_t index_id : ids) {
469       operands.push_back({SPV_OPERAND_TYPE_ID, {index_id}});
470     }
471 
472     // TODO(1841): Handle id overflow.
473     std::unique_ptr<Instruction> new_inst(
474         new Instruction(GetContext(), SpvOpAccessChain, type_id,
475                         GetContext()->TakeNextId(), operands));
476     return AddInstruction(std::move(new_inst));
477   }
478 
AddLoad(uint32_t type_id,uint32_t base_ptr_id)479   Instruction* AddLoad(uint32_t type_id, uint32_t base_ptr_id) {
480     std::vector<Operand> operands;
481     operands.push_back({SPV_OPERAND_TYPE_ID, {base_ptr_id}});
482 
483     // TODO(1841): Handle id overflow.
484     std::unique_ptr<Instruction> new_inst(
485         new Instruction(GetContext(), SpvOpLoad, type_id,
486                         GetContext()->TakeNextId(), operands));
487     return AddInstruction(std::move(new_inst));
488   }
489 
AddStore(uint32_t ptr_id,uint32_t obj_id)490   Instruction* AddStore(uint32_t ptr_id, uint32_t obj_id) {
491     std::vector<Operand> operands;
492     operands.push_back({SPV_OPERAND_TYPE_ID, {ptr_id}});
493     operands.push_back({SPV_OPERAND_TYPE_ID, {obj_id}});
494 
495     std::unique_ptr<Instruction> new_inst(
496         new Instruction(GetContext(), SpvOpStore, 0, 0, operands));
497     return AddInstruction(std::move(new_inst));
498   }
499 
AddFunctionCall(uint32_t result_type,uint32_t function,const std::vector<uint32_t> & parameters)500   Instruction* AddFunctionCall(uint32_t result_type, uint32_t function,
501                                const std::vector<uint32_t>& parameters) {
502     std::vector<Operand> operands;
503     operands.push_back({SPV_OPERAND_TYPE_ID, {function}});
504     for (uint32_t id : parameters) {
505       operands.push_back({SPV_OPERAND_TYPE_ID, {id}});
506     }
507 
508     uint32_t result_id = GetContext()->TakeNextId();
509     if (result_id == 0) {
510       return nullptr;
511     }
512     std::unique_ptr<Instruction> new_inst(new Instruction(
513         GetContext(), SpvOpFunctionCall, result_type, result_id, operands));
514     return AddInstruction(std::move(new_inst));
515   }
516 
AddVectorShuffle(uint32_t result_type,uint32_t vec1,uint32_t vec2,const std::vector<uint32_t> & components)517   Instruction* AddVectorShuffle(uint32_t result_type, uint32_t vec1,
518                                 uint32_t vec2,
519                                 const std::vector<uint32_t>& components) {
520     std::vector<Operand> operands;
521     operands.push_back({SPV_OPERAND_TYPE_ID, {vec1}});
522     operands.push_back({SPV_OPERAND_TYPE_ID, {vec2}});
523     for (uint32_t id : components) {
524       operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {id}});
525     }
526 
527     uint32_t result_id = GetContext()->TakeNextId();
528     if (result_id == 0) {
529       return nullptr;
530     }
531 
532     std::unique_ptr<Instruction> new_inst(new Instruction(
533         GetContext(), SpvOpVectorShuffle, result_type, result_id, operands));
534     return AddInstruction(std::move(new_inst));
535   }
536 
AddNaryExtendedInstruction(uint32_t result_type,uint32_t set,uint32_t instruction,const std::vector<uint32_t> & ext_operands)537   Instruction* AddNaryExtendedInstruction(
538       uint32_t result_type, uint32_t set, uint32_t instruction,
539       const std::vector<uint32_t>& ext_operands) {
540     std::vector<Operand> operands;
541     operands.push_back({SPV_OPERAND_TYPE_ID, {set}});
542     operands.push_back(
543         {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, {instruction}});
544     for (uint32_t id : ext_operands) {
545       operands.push_back({SPV_OPERAND_TYPE_ID, {id}});
546     }
547 
548     uint32_t result_id = GetContext()->TakeNextId();
549     if (result_id == 0) {
550       return nullptr;
551     }
552 
553     std::unique_ptr<Instruction> new_inst(new Instruction(
554         GetContext(), SpvOpExtInst, result_type, result_id, operands));
555     return AddInstruction(std::move(new_inst));
556   }
557 
558   // Inserts the new instruction before the insertion point.
AddInstruction(std::unique_ptr<Instruction> && insn)559   Instruction* AddInstruction(std::unique_ptr<Instruction>&& insn) {
560     Instruction* insn_ptr = &*insert_before_.InsertBefore(std::move(insn));
561     UpdateInstrToBlockMapping(insn_ptr);
562     UpdateDefUseMgr(insn_ptr);
563     return insn_ptr;
564   }
565 
566   // Returns the insertion point iterator.
GetInsertPoint()567   InsertionPointTy GetInsertPoint() { return insert_before_; }
568 
569   // Change the insertion point to insert before the instruction
570   // |insert_before|.
SetInsertPoint(Instruction * insert_before)571   void SetInsertPoint(Instruction* insert_before) {
572     parent_ = context_->get_instr_block(insert_before);
573     insert_before_ = InsertionPointTy(insert_before);
574   }
575 
576   // Change the insertion point to insert at the end of the basic block
577   // |parent_block|.
SetInsertPoint(BasicBlock * parent_block)578   void SetInsertPoint(BasicBlock* parent_block) {
579     parent_ = parent_block;
580     insert_before_ = parent_block->end();
581   }
582 
583   // Returns the context which instructions are constructed for.
GetContext()584   IRContext* GetContext() const { return context_; }
585 
586   // Returns the set of preserved analyses.
GetPreservedAnalysis()587   inline IRContext::Analysis GetPreservedAnalysis() const {
588     return preserved_analyses_;
589   }
590 
591  private:
InstructionBuilder(IRContext * context,BasicBlock * parent,InsertionPointTy insert_before,IRContext::Analysis preserved_analyses)592   InstructionBuilder(IRContext* context, BasicBlock* parent,
593                      InsertionPointTy insert_before,
594                      IRContext::Analysis preserved_analyses)
595       : context_(context),
596         parent_(parent),
597         insert_before_(insert_before),
598         preserved_analyses_(preserved_analyses) {
599     assert(!(preserved_analyses_ & ~(IRContext::kAnalysisDefUse |
600                                      IRContext::kAnalysisInstrToBlockMapping)));
601   }
602 
603   // Returns true if the users requested to update |analysis|.
IsAnalysisUpdateRequested(IRContext::Analysis analysis)604   inline bool IsAnalysisUpdateRequested(IRContext::Analysis analysis) const {
605     if (!GetContext()->AreAnalysesValid(analysis)) {
606       // Do not try to update something that is not built.
607       return false;
608     }
609     return preserved_analyses_ & analysis;
610   }
611 
612   // Updates the def/use manager if the user requested it. If an update was not
613   // requested, this function does nothing.
UpdateDefUseMgr(Instruction * insn)614   inline void UpdateDefUseMgr(Instruction* insn) {
615     if (IsAnalysisUpdateRequested(IRContext::kAnalysisDefUse))
616       GetContext()->get_def_use_mgr()->AnalyzeInstDefUse(insn);
617   }
618 
619   // Updates the instruction to block analysis if the user requested it. If
620   // an update was not requested, this function does nothing.
UpdateInstrToBlockMapping(Instruction * insn)621   inline void UpdateInstrToBlockMapping(Instruction* insn) {
622     if (IsAnalysisUpdateRequested(IRContext::kAnalysisInstrToBlockMapping) &&
623         parent_)
624       GetContext()->set_instr_block(insn, parent_);
625   }
626 
627   IRContext* context_;
628   BasicBlock* parent_;
629   InsertionPointTy insert_before_;
630   const IRContext::Analysis preserved_analyses_;
631 };
632 
633 }  // namespace opt
634 }  // namespace spvtools
635 
636 #endif  // SOURCE_OPT_IR_BUILDER_H_
637