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
28namespace spvtools {
29namespace opt {
30
31// In SPIR-V, ids are encoded as uint16_t, this id is guaranteed to be always
32// invalid.
33const 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
40class 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
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
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
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
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
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
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.
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.
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.
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.
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.
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|.
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.
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|.
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.
386 Instruction* GetUintConstant(uint32_t value) {
387 return GetIntConstant<uint32_t>(value, false);
388 }
389
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>
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
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.
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
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
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
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
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
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
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.
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.
559 InsertionPointTy GetInsertPoint() { return insert_before_; }
560
561 // Change the insertion point to insert before the instruction
562 // |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|.
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.
576 IRContext* GetContext() const { return context_; }
577
578 // Returns the set of preserved analyses.
579 inline IRContext::Analysis GetPreservedAnalysis() const {
580 return preserved_analyses_;
581 }
582
583 private:
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|.
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 he did not request
605 // an update, this function does nothing.
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 he
612 // did not request an update, this function does nothing.
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