| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735 |
- // Copyright (c) 2018 Google Inc.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #ifndef SOURCE_OPT_IR_BUILDER_H_
- #define SOURCE_OPT_IR_BUILDER_H_
- #include <cassert>
- #include <limits>
- #include <memory>
- #include <utility>
- #include <vector>
- #include "source/opt/basic_block.h"
- #include "source/opt/constants.h"
- #include "source/opt/instruction.h"
- #include "source/opt/ir_context.h"
- namespace spvtools {
- namespace opt {
- // In SPIR-V, ids are encoded as uint16_t, this id is guaranteed to be always
- // invalid.
- constexpr uint32_t kInvalidId = std::numeric_limits<uint32_t>::max();
- // Helper class to abstract instruction construction and insertion.
- // The instruction builder can preserve the following analyses (specified via
- // the constructors):
- // - Def-use analysis
- // - Instruction to block analysis
- class InstructionBuilder {
- public:
- using InsertionPointTy = BasicBlock::iterator;
- // Creates an InstructionBuilder, all new instructions will be inserted before
- // the instruction |insert_before|.
- InstructionBuilder(
- IRContext* context, Instruction* insert_before,
- IRContext::Analysis preserved_analyses = IRContext::kAnalysisNone)
- : InstructionBuilder(context, context->get_instr_block(insert_before),
- InsertionPointTy(insert_before),
- preserved_analyses) {}
- // Creates an InstructionBuilder, all new instructions will be inserted at the
- // end of the basic block |parent_block|.
- InstructionBuilder(
- IRContext* context, BasicBlock* parent_block,
- IRContext::Analysis preserved_analyses = IRContext::kAnalysisNone)
- : InstructionBuilder(context, parent_block, parent_block->end(),
- preserved_analyses) {}
- Instruction* AddNullaryOp(uint32_t type_id, spv::Op opcode) {
- uint32_t result_id = 0;
- if (type_id != 0) {
- result_id = GetContext()->TakeNextId();
- if (result_id == 0) {
- return nullptr;
- }
- }
- std::unique_ptr<Instruction> new_inst(
- new Instruction(GetContext(), opcode, type_id, result_id, {}));
- return AddInstruction(std::move(new_inst));
- }
- Instruction* AddUnaryOp(uint32_t type_id, spv::Op opcode, uint32_t operand1) {
- uint32_t result_id = 0;
- if (type_id != 0) {
- result_id = GetContext()->TakeNextId();
- if (result_id == 0) {
- return nullptr;
- }
- }
- std::unique_ptr<Instruction> newUnOp(new Instruction(
- GetContext(), opcode, type_id, result_id,
- {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}}));
- return AddInstruction(std::move(newUnOp));
- }
- Instruction* AddBinaryOp(uint32_t type_id, spv::Op opcode, uint32_t operand1,
- uint32_t operand2) {
- uint32_t result_id = 0;
- if (type_id != 0) {
- result_id = GetContext()->TakeNextId();
- if (result_id == 0) {
- return nullptr;
- }
- }
- std::unique_ptr<Instruction> newBinOp(new Instruction(
- GetContext(), opcode, type_id,
- opcode == spv::Op::OpStore ? 0 : result_id,
- {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}},
- {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}}}));
- return AddInstruction(std::move(newBinOp));
- }
- Instruction* AddTernaryOp(uint32_t type_id, spv::Op opcode, uint32_t operand1,
- uint32_t operand2, uint32_t operand3) {
- uint32_t result_id = 0;
- if (type_id != 0) {
- result_id = GetContext()->TakeNextId();
- if (result_id == 0) {
- return nullptr;
- }
- }
- std::unique_ptr<Instruction> newTernOp(new Instruction(
- GetContext(), opcode, type_id, result_id,
- {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}},
- {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}},
- {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand3}}}));
- return AddInstruction(std::move(newTernOp));
- }
- Instruction* AddQuadOp(uint32_t type_id, spv::Op opcode, uint32_t operand1,
- uint32_t operand2, uint32_t operand3,
- uint32_t operand4) {
- uint32_t result_id = 0;
- if (type_id != 0) {
- result_id = GetContext()->TakeNextId();
- if (result_id == 0) {
- return nullptr;
- }
- }
- std::unique_ptr<Instruction> newQuadOp(new Instruction(
- GetContext(), opcode, type_id, result_id,
- {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}},
- {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}},
- {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand3}},
- {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand4}}}));
- return AddInstruction(std::move(newQuadOp));
- }
- Instruction* AddIdLiteralOp(uint32_t type_id, spv::Op opcode, uint32_t id,
- uint32_t uliteral) {
- uint32_t result_id = 0;
- if (type_id != 0) {
- result_id = GetContext()->TakeNextId();
- if (result_id == 0) {
- return nullptr;
- }
- }
- std::unique_ptr<Instruction> newBinOp(new Instruction(
- GetContext(), opcode, type_id, result_id,
- {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {id}},
- {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {uliteral}}}));
- return AddInstruction(std::move(newBinOp));
- }
- // Creates an N-ary instruction of |opcode|.
- // |typid| must be the id of the instruction's type.
- // |operands| must be a sequence of operand ids.
- // Use |result| for the result id if non-zero.
- Instruction* AddNaryOp(uint32_t type_id, spv::Op opcode,
- const std::vector<uint32_t>& operands,
- uint32_t result = 0) {
- std::vector<Operand> ops;
- for (size_t i = 0; i < operands.size(); i++) {
- ops.push_back({SPV_OPERAND_TYPE_ID, {operands[i]}});
- }
- // TODO(1841): Handle id overflow.
- std::unique_ptr<Instruction> new_inst(new Instruction(
- GetContext(), opcode, type_id,
- result != 0 ? result : GetContext()->TakeNextId(), ops));
- return AddInstruction(std::move(new_inst));
- }
- // Creates a new selection merge instruction.
- // The id |merge_id| is the merge basic block id.
- Instruction* AddSelectionMerge(
- uint32_t merge_id, uint32_t selection_control = static_cast<uint32_t>(
- spv::SelectionControlMask::MaskNone)) {
- std::unique_ptr<Instruction> new_branch_merge(new Instruction(
- GetContext(), spv::Op::OpSelectionMerge, 0, 0,
- {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}},
- {spv_operand_type_t::SPV_OPERAND_TYPE_SELECTION_CONTROL,
- {selection_control}}}));
- return AddInstruction(std::move(new_branch_merge));
- }
- // Creates a new loop merge instruction.
- // The id |merge_id| is the basic block id of the merge block.
- // |continue_id| is the id of the continue block.
- // |loop_control| are the loop control flags to be added to the instruction.
- Instruction* AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
- uint32_t loop_control = static_cast<uint32_t>(
- spv::LoopControlMask::MaskNone)) {
- std::unique_ptr<Instruction> new_branch_merge(new Instruction(
- GetContext(), spv::Op::OpLoopMerge, 0, 0,
- {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}},
- {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {continue_id}},
- {spv_operand_type_t::SPV_OPERAND_TYPE_LOOP_CONTROL, {loop_control}}}));
- return AddInstruction(std::move(new_branch_merge));
- }
- // Creates a new branch instruction to |label_id|.
- // Note that the user must make sure the final basic block is
- // well formed.
- Instruction* AddBranch(uint32_t label_id) {
- std::unique_ptr<Instruction> new_branch(new Instruction(
- GetContext(), spv::Op::OpBranch, 0, 0,
- {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {label_id}}}));
- return AddInstruction(std::move(new_branch));
- }
- // Creates a new conditional instruction and the associated selection merge
- // instruction if requested.
- // The id |cond_id| is the id of the condition instruction, must be of
- // type bool.
- // The id |true_id| is the id of the basic block to branch to if the condition
- // is true.
- // The id |false_id| is the id of the basic block to branch to if the
- // condition is false.
- // The id |merge_id| is the id of the merge basic block for the selection
- // merge instruction. If |merge_id| equals kInvalidId then no selection merge
- // instruction will be created.
- // The value |selection_control| is the selection control flag for the
- // selection merge instruction.
- // Note that the user must make sure the final basic block is
- // well formed.
- Instruction* AddConditionalBranch(
- uint32_t cond_id, uint32_t true_id, uint32_t false_id,
- uint32_t merge_id = kInvalidId,
- uint32_t selection_control =
- static_cast<uint32_t>(spv::SelectionControlMask::MaskNone)) {
- if (merge_id != kInvalidId) {
- AddSelectionMerge(merge_id, selection_control);
- }
- std::unique_ptr<Instruction> new_branch(new Instruction(
- GetContext(), spv::Op::OpBranchConditional, 0, 0,
- {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {cond_id}},
- {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {true_id}},
- {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {false_id}}}));
- return AddInstruction(std::move(new_branch));
- }
- // Creates a new switch instruction and the associated selection merge
- // instruction if requested.
- // The id |selector_id| is the id of the selector instruction, must be of
- // type int.
- // The id |default_id| is the id of the default basic block to branch to.
- // The vector |targets| is the pair of literal/branch id.
- // The id |merge_id| is the id of the merge basic block for the selection
- // merge instruction. If |merge_id| equals kInvalidId then no selection merge
- // instruction will be created.
- // The value |selection_control| is the selection control flag for the
- // selection merge instruction.
- // Note that the user must make sure the final basic block is
- // well formed.
- Instruction* AddSwitch(
- uint32_t selector_id, uint32_t default_id,
- const std::vector<std::pair<Operand::OperandData, uint32_t>>& targets,
- uint32_t merge_id = kInvalidId,
- uint32_t selection_control =
- static_cast<uint32_t>(spv::SelectionControlMask::MaskNone)) {
- if (merge_id != kInvalidId) {
- AddSelectionMerge(merge_id, selection_control);
- }
- std::vector<Operand> operands;
- operands.emplace_back(
- Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {selector_id}});
- operands.emplace_back(
- Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {default_id}});
- for (auto& target : targets) {
- operands.emplace_back(
- Operand{spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
- target.first});
- operands.emplace_back(
- Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {target.second}});
- }
- std::unique_ptr<Instruction> new_switch(
- new Instruction(GetContext(), spv::Op::OpSwitch, 0, 0, operands));
- return AddInstruction(std::move(new_switch));
- }
- // Creates a phi instruction.
- // The id |type| must be the id of the phi instruction's type.
- // The vector |incomings| must be a sequence of pairs of <definition id,
- // parent id>.
- Instruction* AddPhi(uint32_t type, const std::vector<uint32_t>& incomings,
- uint32_t result = 0) {
- assert(incomings.size() % 2 == 0 && "A sequence of pairs is expected");
- return AddNaryOp(type, spv::Op::OpPhi, incomings, result);
- }
- // Creates an addition instruction.
- // The id |type| must be the id of the instruction's type, must be the same as
- // |op1| and |op2| types.
- // The id |op1| is the left hand side of the operation.
- // The id |op2| is the right hand side of the operation.
- Instruction* AddIAdd(uint32_t type, uint32_t op1, uint32_t op2) {
- // TODO(1841): Handle id overflow.
- std::unique_ptr<Instruction> inst(new Instruction(
- GetContext(), spv::Op::OpIAdd, type, GetContext()->TakeNextId(),
- {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}}));
- return AddInstruction(std::move(inst));
- }
- // Creates a less than instruction for unsigned integer.
- // The id |op1| is the left hand side of the operation.
- // The id |op2| is the right hand side of the operation.
- // It is assumed that |op1| and |op2| have the same underlying type.
- Instruction* AddULessThan(uint32_t op1, uint32_t op2) {
- analysis::Bool bool_type;
- uint32_t type = GetContext()->get_type_mgr()->GetId(&bool_type);
- // TODO(1841): Handle id overflow.
- std::unique_ptr<Instruction> inst(new Instruction(
- GetContext(), spv::Op::OpULessThan, type, GetContext()->TakeNextId(),
- {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}}));
- return AddInstruction(std::move(inst));
- }
- // Creates a less than instruction for signed integer.
- // The id |op1| is the left hand side of the operation.
- // The id |op2| is the right hand side of the operation.
- // It is assumed that |op1| and |op2| have the same underlying type.
- Instruction* AddSLessThan(uint32_t op1, uint32_t op2) {
- analysis::Bool bool_type;
- uint32_t type = GetContext()->get_type_mgr()->GetId(&bool_type);
- // TODO(1841): Handle id overflow.
- std::unique_ptr<Instruction> inst(new Instruction(
- GetContext(), spv::Op::OpSLessThan, type, GetContext()->TakeNextId(),
- {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}}));
- return AddInstruction(std::move(inst));
- }
- // Creates an OpILessThan or OpULessThen instruction depending on the sign of
- // |op1|. The id |op1| is the left hand side of the operation. The id |op2| is
- // the right hand side of the operation. It is assumed that |op1| and |op2|
- // have the same underlying type.
- Instruction* AddLessThan(uint32_t op1, uint32_t op2) {
- Instruction* op1_insn = context_->get_def_use_mgr()->GetDef(op1);
- analysis::Type* type =
- GetContext()->get_type_mgr()->GetType(op1_insn->type_id());
- analysis::Integer* int_type = type->AsInteger();
- assert(int_type && "Operand is not of int type");
- if (int_type->IsSigned())
- return AddSLessThan(op1, op2);
- else
- return AddULessThan(op1, op2);
- }
- // Creates a select instruction.
- // |type| must match the types of |true_value| and |false_value|. It is up to
- // the caller to ensure that |cond| is a correct type (bool or vector of
- // bool) for |type|.
- Instruction* AddSelect(uint32_t type, uint32_t cond, uint32_t true_value,
- uint32_t false_value) {
- // TODO(1841): Handle id overflow.
- std::unique_ptr<Instruction> select(new Instruction(
- GetContext(), spv::Op::OpSelect, type, GetContext()->TakeNextId(),
- std::initializer_list<Operand>{{SPV_OPERAND_TYPE_ID, {cond}},
- {SPV_OPERAND_TYPE_ID, {true_value}},
- {SPV_OPERAND_TYPE_ID, {false_value}}}));
- return AddInstruction(std::move(select));
- }
- // Returns a pointer to the definition of a signed 32-bit integer constant
- // with the given value. Returns |nullptr| if the constant does not exist and
- // cannot be created.
- Instruction* GetSintConstant(int32_t value) {
- return GetIntConstant<int32_t>(value, true);
- }
- // Create a composite construct.
- // |type| should be a composite type and the number of elements it has should
- // match the size od |ids|.
- Instruction* AddCompositeConstruct(uint32_t type,
- const std::vector<uint32_t>& ids) {
- std::vector<Operand> ops;
- for (auto id : ids) {
- ops.emplace_back(SPV_OPERAND_TYPE_ID,
- std::initializer_list<uint32_t>{id});
- }
- // TODO(1841): Handle id overflow.
- std::unique_ptr<Instruction> construct(
- new Instruction(GetContext(), spv::Op::OpCompositeConstruct, type,
- GetContext()->TakeNextId(), ops));
- return AddInstruction(std::move(construct));
- }
- // Returns a pointer to the definition of an unsigned 32-bit integer constant
- // with the given value. Returns |nullptr| if the constant does not exist and
- // cannot be created.
- Instruction* GetUintConstant(uint32_t value) {
- return GetIntConstant<uint32_t>(value, false);
- }
- uint32_t GetUintConstantId(uint32_t value) {
- Instruction* uint_inst = GetUintConstant(value);
- return (uint_inst != nullptr ? uint_inst->result_id() : 0);
- }
- // Adds either a signed or unsigned 32 bit integer constant to the binary
- // depending on the |sign|. If |sign| is true then the value is added as a
- // signed constant otherwise as an unsigned constant. If |sign| is false the
- // value must not be a negative number. Returns false if the constant does
- // not exists and could be be created.
- template <typename T>
- Instruction* GetIntConstant(T value, bool sign) {
- // Assert that we are not trying to store a negative number in an unsigned
- // type.
- if (!sign)
- assert(value >= 0 &&
- "Trying to add a signed integer with an unsigned type!");
- analysis::Integer int_type{32, sign};
- // Get or create the integer type. This rebuilds the type and manages the
- // memory for the rebuilt type.
- uint32_t type_id =
- GetContext()->get_type_mgr()->GetTypeInstruction(&int_type);
- if (type_id == 0) {
- return nullptr;
- }
- // Get the memory managed type so that it is safe to be stored by
- // GetConstant.
- analysis::Type* rebuilt_type =
- GetContext()->get_type_mgr()->GetType(type_id);
- // Even if the value is negative we need to pass the bit pattern as a
- // uint32_t to GetConstant.
- uint32_t word = value;
- // Create the constant value.
- const analysis::Constant* constant =
- GetContext()->get_constant_mgr()->GetConstant(rebuilt_type, {word});
- // Create the OpConstant instruction using the type and the value.
- return GetContext()->get_constant_mgr()->GetDefiningInstruction(constant);
- }
- Instruction* GetBoolConstant(bool value) {
- analysis::Bool type;
- uint32_t type_id = GetContext()->get_type_mgr()->GetTypeInstruction(&type);
- analysis::Type* rebuilt_type =
- GetContext()->get_type_mgr()->GetType(type_id);
- uint32_t word = value;
- const analysis::Constant* constant =
- GetContext()->get_constant_mgr()->GetConstant(rebuilt_type, {word});
- return GetContext()->get_constant_mgr()->GetDefiningInstruction(constant);
- }
- uint32_t GetBoolConstantId(bool value) {
- Instruction* inst = GetBoolConstant(value);
- return (inst != nullptr ? inst->result_id() : 0);
- }
- Instruction* AddCompositeExtract(uint32_t type, uint32_t id_of_composite,
- const std::vector<uint32_t>& index_list) {
- std::vector<Operand> operands;
- operands.push_back({SPV_OPERAND_TYPE_ID, {id_of_composite}});
- for (uint32_t index : index_list) {
- operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {index}});
- }
- // TODO(1841): Handle id overflow.
- std::unique_ptr<Instruction> new_inst(
- new Instruction(GetContext(), spv::Op::OpCompositeExtract, type,
- GetContext()->TakeNextId(), operands));
- return AddInstruction(std::move(new_inst));
- }
- // Creates an unreachable instruction.
- Instruction* AddUnreachable() {
- std::unique_ptr<Instruction> select(
- new Instruction(GetContext(), spv::Op::OpUnreachable, 0, 0,
- std::initializer_list<Operand>{}));
- return AddInstruction(std::move(select));
- }
- Instruction* AddOpcodeAccessChain(spv::Op opcode, uint32_t type_id,
- uint32_t base_ptr_id,
- const std::vector<uint32_t>& ids) {
- assert(opcode == spv::Op::OpAccessChain ||
- opcode == spv::Op::OpInBoundsAccessChain);
- std::vector<Operand> operands;
- operands.push_back({SPV_OPERAND_TYPE_ID, {base_ptr_id}});
- for (uint32_t index_id : ids) {
- operands.push_back({SPV_OPERAND_TYPE_ID, {index_id}});
- }
- // TODO(1841): Handle id overflow.
- std::unique_ptr<Instruction> new_inst(new Instruction(
- GetContext(), opcode, type_id, GetContext()->TakeNextId(), operands));
- return AddInstruction(std::move(new_inst));
- }
- Instruction* AddAccessChain(uint32_t type_id, uint32_t base_ptr_id,
- const std::vector<uint32_t>& ids) {
- return AddOpcodeAccessChain(spv::Op::OpAccessChain, type_id, base_ptr_id,
- ids);
- }
- Instruction* AddInBoundsAccessChain(uint32_t type_id, uint32_t base_ptr_id,
- const std::vector<uint32_t>& ids) {
- return AddOpcodeAccessChain(spv::Op::OpInBoundsAccessChain, type_id,
- base_ptr_id, ids);
- }
- Instruction* AddLoad(uint32_t type_id, uint32_t base_ptr_id,
- uint32_t alignment = 0) {
- std::vector<Operand> operands;
- operands.push_back({SPV_OPERAND_TYPE_ID, {base_ptr_id}});
- if (alignment != 0) {
- operands.push_back(
- {SPV_OPERAND_TYPE_MEMORY_ACCESS,
- {static_cast<uint32_t>(spv::MemoryAccessMask::Aligned)}});
- operands.push_back({SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, {alignment}});
- }
- // TODO(1841): Handle id overflow.
- std::unique_ptr<Instruction> new_inst(
- new Instruction(GetContext(), spv::Op::OpLoad, type_id,
- GetContext()->TakeNextId(), operands));
- return AddInstruction(std::move(new_inst));
- }
- Instruction* AddCopyObject(uint32_t type_id, uint32_t value_id) {
- std::vector<Operand> operands{{SPV_OPERAND_TYPE_ID, {value_id}}};
- // TODO(1841): Handle id overflow.
- std::unique_ptr<Instruction> new_inst(
- new Instruction(GetContext(), spv::Op::OpCopyObject, type_id,
- GetContext()->TakeNextId(), operands));
- return AddInstruction(std::move(new_inst));
- }
- Instruction* AddVariable(uint32_t type_id, uint32_t storage_class) {
- std::vector<Operand> operands;
- operands.push_back({SPV_OPERAND_TYPE_STORAGE_CLASS, {storage_class}});
- std::unique_ptr<Instruction> new_inst(
- new Instruction(GetContext(), spv::Op::OpVariable, type_id,
- GetContext()->TakeNextId(), operands));
- return AddInstruction(std::move(new_inst));
- }
- Instruction* AddStore(uint32_t ptr_id, uint32_t obj_id) {
- std::vector<Operand> operands;
- operands.push_back({SPV_OPERAND_TYPE_ID, {ptr_id}});
- operands.push_back({SPV_OPERAND_TYPE_ID, {obj_id}});
- std::unique_ptr<Instruction> new_inst(
- new Instruction(GetContext(), spv::Op::OpStore, 0, 0, operands));
- return AddInstruction(std::move(new_inst));
- }
- Instruction* AddFunctionCall(uint32_t result_type, uint32_t function,
- const std::vector<uint32_t>& parameters) {
- std::vector<Operand> operands;
- operands.push_back({SPV_OPERAND_TYPE_ID, {function}});
- for (uint32_t id : parameters) {
- operands.push_back({SPV_OPERAND_TYPE_ID, {id}});
- }
- uint32_t result_id = GetContext()->TakeNextId();
- if (result_id == 0) {
- return nullptr;
- }
- std::unique_ptr<Instruction> new_inst(
- new Instruction(GetContext(), spv::Op::OpFunctionCall, result_type,
- result_id, operands));
- return AddInstruction(std::move(new_inst));
- }
- Instruction* AddVectorShuffle(uint32_t result_type, uint32_t vec1,
- uint32_t vec2,
- const std::vector<uint32_t>& components) {
- std::vector<Operand> operands;
- operands.push_back({SPV_OPERAND_TYPE_ID, {vec1}});
- operands.push_back({SPV_OPERAND_TYPE_ID, {vec2}});
- for (uint32_t id : components) {
- operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {id}});
- }
- uint32_t result_id = GetContext()->TakeNextId();
- if (result_id == 0) {
- return nullptr;
- }
- std::unique_ptr<Instruction> new_inst(
- new Instruction(GetContext(), spv::Op::OpVectorShuffle, result_type,
- result_id, operands));
- return AddInstruction(std::move(new_inst));
- }
- Instruction* AddDecoration(uint32_t target_id, spv::Decoration d,
- const std::vector<uint32_t>& literals) {
- std::vector<Operand> operands;
- operands.push_back({SPV_OPERAND_TYPE_ID, {target_id}});
- operands.push_back({SPV_OPERAND_TYPE_DECORATION, {uint32_t(d)}});
- for (uint32_t literal : literals) {
- operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {literal}});
- }
- std::unique_ptr<Instruction> new_inst(
- new Instruction(GetContext(), spv::Op::OpDecorate, 0, 0, operands));
- // Decorations are annotation instructions. Add it via the IR context,
- // so the decoration manager will be updated.
- // Decorations don't belong to basic blocks, so there is no need
- // to update the instruction to block mapping.
- Instruction* result = new_inst.get();
- GetContext()->AddAnnotationInst(std::move(new_inst));
- return result;
- }
- Instruction* AddNaryExtendedInstruction(
- uint32_t result_type, uint32_t set, uint32_t instruction,
- const std::vector<uint32_t>& ext_operands) {
- std::vector<Operand> operands;
- operands.push_back({SPV_OPERAND_TYPE_ID, {set}});
- operands.push_back(
- {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, {instruction}});
- for (uint32_t id : ext_operands) {
- operands.push_back({SPV_OPERAND_TYPE_ID, {id}});
- }
- uint32_t result_id = GetContext()->TakeNextId();
- if (result_id == 0) {
- return nullptr;
- }
- std::unique_ptr<Instruction> new_inst(new Instruction(
- GetContext(), spv::Op::OpExtInst, result_type, result_id, operands));
- return AddInstruction(std::move(new_inst));
- }
- Instruction* AddSampledImage(uint32_t sampled_image_type_id,
- uint32_t image_id, uint32_t sampler_id) {
- std::vector<Operand> operands;
- operands.push_back({SPV_OPERAND_TYPE_ID, {image_id}});
- operands.push_back({SPV_OPERAND_TYPE_ID, {sampler_id}});
- uint32_t result_id = GetContext()->TakeNextId();
- if (result_id == 0) {
- return nullptr;
- }
- std::unique_ptr<Instruction> new_inst(
- new Instruction(GetContext(), spv::Op::OpSampledImage,
- sampled_image_type_id, result_id, operands));
- return AddInstruction(std::move(new_inst));
- }
- // Inserts the new instruction before the insertion point.
- Instruction* AddInstruction(std::unique_ptr<Instruction>&& insn) {
- Instruction* insn_ptr = &*insert_before_.InsertBefore(std::move(insn));
- UpdateInstrToBlockMapping(insn_ptr);
- UpdateDefUseMgr(insn_ptr);
- return insn_ptr;
- }
- // Returns the insertion point iterator.
- InsertionPointTy GetInsertPoint() { return insert_before_; }
- // Change the insertion point to insert before the instruction
- // |insert_before|.
- void SetInsertPoint(Instruction* insert_before) {
- parent_ = context_->get_instr_block(insert_before);
- insert_before_ = InsertionPointTy(insert_before);
- }
- // Change the insertion point to insert at the end of the basic block
- // |parent_block|.
- void SetInsertPoint(BasicBlock* parent_block) {
- parent_ = parent_block;
- insert_before_ = parent_block->end();
- }
- // Returns the context which instructions are constructed for.
- IRContext* GetContext() const { return context_; }
- // Returns the set of preserved analyses.
- inline IRContext::Analysis GetPreservedAnalysis() const {
- return preserved_analyses_;
- }
- private:
- InstructionBuilder(IRContext* context, BasicBlock* parent,
- InsertionPointTy insert_before,
- IRContext::Analysis preserved_analyses)
- : context_(context),
- parent_(parent),
- insert_before_(insert_before),
- preserved_analyses_(preserved_analyses) {
- assert(!(preserved_analyses_ & ~(IRContext::kAnalysisDefUse |
- IRContext::kAnalysisInstrToBlockMapping)));
- }
- // Returns true if the users requested to update |analysis|.
- inline bool IsAnalysisUpdateRequested(IRContext::Analysis analysis) const {
- if (!GetContext()->AreAnalysesValid(analysis)) {
- // Do not try to update something that is not built.
- return false;
- }
- return preserved_analyses_ & analysis;
- }
- // Updates the def/use manager if the user requested it. If an update was not
- // requested, this function does nothing.
- inline void UpdateDefUseMgr(Instruction* insn) {
- if (IsAnalysisUpdateRequested(IRContext::kAnalysisDefUse))
- GetContext()->get_def_use_mgr()->AnalyzeInstDefUse(insn);
- }
- // Updates the instruction to block analysis if the user requested it. If
- // an update was not requested, this function does nothing.
- inline void UpdateInstrToBlockMapping(Instruction* insn) {
- if (IsAnalysisUpdateRequested(IRContext::kAnalysisInstrToBlockMapping) &&
- parent_)
- GetContext()->set_instr_block(insn, parent_);
- }
- IRContext* context_;
- BasicBlock* parent_;
- InsertionPointTy insert_before_;
- const IRContext::Analysis preserved_analyses_;
- };
- } // namespace opt
- } // namespace spvtools
- #endif // SOURCE_OPT_IR_BUILDER_H_
|