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