1 // Copyright (c) 2018 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef SOURCE_OPT_IR_BUILDER_H_ 16 #define SOURCE_OPT_IR_BUILDER_H_ 17 18 #include <limits> 19 #include <memory> 20 #include <utility> 21 #include <vector> 22 23 #include "source/opt/basic_block.h" 24 #include "source/opt/constants.h" 25 #include "source/opt/instruction.h" 26 #include "source/opt/ir_context.h" 27 28 namespace spvtools { 29 namespace opt { 30 31 // In SPIR-V, ids are encoded as uint16_t, this id is guaranteed to be always 32 // invalid. 33 const uint32_t kInvalidId = std::numeric_limits<uint32_t>::max(); 34 35 // Helper class to abstract instruction construction and insertion. 36 // The instruction builder can preserve the following analyses (specified via 37 // the constructors): 38 // - Def-use analysis 39 // - Instruction to block analysis 40 class InstructionBuilder { 41 public: 42 using InsertionPointTy = BasicBlock::iterator; 43 44 // Creates an InstructionBuilder, all new instructions will be inserted before 45 // the instruction |insert_before|. 46 InstructionBuilder( 47 IRContext* context, Instruction* insert_before, 48 IRContext::Analysis preserved_analyses = IRContext::kAnalysisNone) 49 : InstructionBuilder(context, context->get_instr_block(insert_before), 50 InsertionPointTy(insert_before), 51 preserved_analyses) {} 52 53 // Creates an InstructionBuilder, all new instructions will be inserted at the 54 // end of the basic block |parent_block|. 55 InstructionBuilder( 56 IRContext* context, BasicBlock* parent_block, 57 IRContext::Analysis preserved_analyses = IRContext::kAnalysisNone) 58 : InstructionBuilder(context, parent_block, parent_block->end(), 59 preserved_analyses) {} 60 AddNullaryOp(uint32_t type_id,SpvOp opcode)61 Instruction* AddNullaryOp(uint32_t type_id, SpvOp opcode) { 62 uint32_t result_id = 0; 63 if (type_id != 0) { 64 result_id = GetContext()->TakeNextId(); 65 if (result_id == 0) { 66 return nullptr; 67 } 68 } 69 std::unique_ptr<Instruction> new_inst( 70 new Instruction(GetContext(), opcode, type_id, result_id, {})); 71 return AddInstruction(std::move(new_inst)); 72 } 73 AddUnaryOp(uint32_t type_id,SpvOp opcode,uint32_t operand1)74 Instruction* AddUnaryOp(uint32_t type_id, SpvOp opcode, uint32_t operand1) { 75 uint32_t result_id = 0; 76 if (type_id != 0) { 77 result_id = GetContext()->TakeNextId(); 78 if (result_id == 0) { 79 return nullptr; 80 } 81 } 82 std::unique_ptr<Instruction> newUnOp(new Instruction( 83 GetContext(), opcode, type_id, result_id, 84 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}})); 85 return AddInstruction(std::move(newUnOp)); 86 } 87 AddBinaryOp(uint32_t type_id,SpvOp opcode,uint32_t operand1,uint32_t operand2)88 Instruction* AddBinaryOp(uint32_t type_id, SpvOp opcode, uint32_t operand1, 89 uint32_t operand2) { 90 uint32_t result_id = 0; 91 if (type_id != 0) { 92 result_id = GetContext()->TakeNextId(); 93 if (result_id == 0) { 94 return nullptr; 95 } 96 } 97 std::unique_ptr<Instruction> newBinOp(new Instruction( 98 GetContext(), opcode, type_id, opcode == SpvOpStore ? 0 : result_id, 99 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}, 100 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}}})); 101 return AddInstruction(std::move(newBinOp)); 102 } 103 AddTernaryOp(uint32_t type_id,SpvOp opcode,uint32_t operand1,uint32_t operand2,uint32_t operand3)104 Instruction* AddTernaryOp(uint32_t type_id, SpvOp opcode, uint32_t operand1, 105 uint32_t operand2, uint32_t operand3) { 106 uint32_t result_id = 0; 107 if (type_id != 0) { 108 result_id = GetContext()->TakeNextId(); 109 if (result_id == 0) { 110 return nullptr; 111 } 112 } 113 std::unique_ptr<Instruction> newTernOp(new Instruction( 114 GetContext(), opcode, type_id, result_id, 115 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}, 116 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}}, 117 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand3}}})); 118 return AddInstruction(std::move(newTernOp)); 119 } 120 AddQuadOp(uint32_t type_id,SpvOp opcode,uint32_t operand1,uint32_t operand2,uint32_t operand3,uint32_t operand4)121 Instruction* AddQuadOp(uint32_t type_id, SpvOp opcode, uint32_t operand1, 122 uint32_t operand2, uint32_t operand3, 123 uint32_t operand4) { 124 uint32_t result_id = 0; 125 if (type_id != 0) { 126 result_id = GetContext()->TakeNextId(); 127 if (result_id == 0) { 128 return nullptr; 129 } 130 } 131 std::unique_ptr<Instruction> newQuadOp(new Instruction( 132 GetContext(), opcode, type_id, result_id, 133 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}, 134 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}}, 135 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand3}}, 136 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand4}}})); 137 return AddInstruction(std::move(newQuadOp)); 138 } 139 AddIdLiteralOp(uint32_t type_id,SpvOp opcode,uint32_t id,uint32_t uliteral)140 Instruction* AddIdLiteralOp(uint32_t type_id, SpvOp opcode, uint32_t id, 141 uint32_t uliteral) { 142 uint32_t result_id = 0; 143 if (type_id != 0) { 144 result_id = GetContext()->TakeNextId(); 145 if (result_id == 0) { 146 return nullptr; 147 } 148 } 149 std::unique_ptr<Instruction> newBinOp(new Instruction( 150 GetContext(), opcode, type_id, result_id, 151 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {id}}, 152 {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {uliteral}}})); 153 return AddInstruction(std::move(newBinOp)); 154 } 155 156 // Creates an N-ary instruction of |opcode|. 157 // |typid| must be the id of the instruction's type. 158 // |operands| must be a sequence of operand ids. 159 // Use |result| for the result id if non-zero. 160 Instruction* AddNaryOp(uint32_t type_id, SpvOp opcode, 161 const std::vector<uint32_t>& operands, 162 uint32_t result = 0) { 163 std::vector<Operand> ops; 164 for (size_t i = 0; i < operands.size(); i++) { 165 ops.push_back({SPV_OPERAND_TYPE_ID, {operands[i]}}); 166 } 167 // TODO(1841): Handle id overflow. 168 std::unique_ptr<Instruction> new_inst(new Instruction( 169 GetContext(), opcode, type_id, 170 result != 0 ? result : GetContext()->TakeNextId(), ops)); 171 return AddInstruction(std::move(new_inst)); 172 } 173 174 // Creates a new selection merge instruction. 175 // The id |merge_id| is the merge basic block id. 176 Instruction* AddSelectionMerge( 177 uint32_t merge_id, 178 uint32_t selection_control = SpvSelectionControlMaskNone) { 179 std::unique_ptr<Instruction> new_branch_merge(new Instruction( 180 GetContext(), SpvOpSelectionMerge, 0, 0, 181 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}}, 182 {spv_operand_type_t::SPV_OPERAND_TYPE_SELECTION_CONTROL, 183 {selection_control}}})); 184 return AddInstruction(std::move(new_branch_merge)); 185 } 186 187 // Creates a new loop merge instruction. 188 // The id |merge_id| is the basic block id of the merge block. 189 // |continue_id| is the id of the continue block. 190 // |loop_control| are the loop control flags to be added to the instruction. 191 Instruction* AddLoopMerge(uint32_t merge_id, uint32_t continue_id, 192 uint32_t loop_control = SpvLoopControlMaskNone) { 193 std::unique_ptr<Instruction> new_branch_merge(new Instruction( 194 GetContext(), SpvOpLoopMerge, 0, 0, 195 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}}, 196 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {continue_id}}, 197 {spv_operand_type_t::SPV_OPERAND_TYPE_LOOP_CONTROL, {loop_control}}})); 198 return AddInstruction(std::move(new_branch_merge)); 199 } 200 201 // Creates a new branch instruction to |label_id|. 202 // Note that the user must make sure the final basic block is 203 // well formed. AddBranch(uint32_t label_id)204 Instruction* AddBranch(uint32_t label_id) { 205 std::unique_ptr<Instruction> new_branch(new Instruction( 206 GetContext(), SpvOpBranch, 0, 0, 207 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {label_id}}})); 208 return AddInstruction(std::move(new_branch)); 209 } 210 211 // Creates a new conditional instruction and the associated selection merge 212 // instruction if requested. 213 // The id |cond_id| is the id of the condition instruction, must be of 214 // type bool. 215 // The id |true_id| is the id of the basic block to branch to if the condition 216 // is true. 217 // The id |false_id| is the id of the basic block to branch to if the 218 // condition is false. 219 // The id |merge_id| is the id of the merge basic block for the selection 220 // merge instruction. If |merge_id| equals kInvalidId then no selection merge 221 // instruction will be created. 222 // The value |selection_control| is the selection control flag for the 223 // selection merge instruction. 224 // Note that the user must make sure the final basic block is 225 // well formed. 226 Instruction* AddConditionalBranch( 227 uint32_t cond_id, uint32_t true_id, uint32_t false_id, 228 uint32_t merge_id = kInvalidId, 229 uint32_t selection_control = SpvSelectionControlMaskNone) { 230 if (merge_id != kInvalidId) { 231 AddSelectionMerge(merge_id, selection_control); 232 } 233 std::unique_ptr<Instruction> new_branch(new Instruction( 234 GetContext(), SpvOpBranchConditional, 0, 0, 235 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {cond_id}}, 236 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {true_id}}, 237 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {false_id}}})); 238 return AddInstruction(std::move(new_branch)); 239 } 240 241 // Creates a new switch instruction and the associated selection merge 242 // instruction if requested. 243 // The id |selector_id| is the id of the selector instruction, must be of 244 // type int. 245 // The id |default_id| is the id of the default basic block to branch to. 246 // The vector |targets| is the pair of literal/branch id. 247 // The id |merge_id| is the id of the merge basic block for the selection 248 // merge instruction. If |merge_id| equals kInvalidId then no selection merge 249 // instruction will be created. 250 // The value |selection_control| is the selection control flag for the 251 // selection merge instruction. 252 // Note that the user must make sure the final basic block is 253 // well formed. 254 Instruction* AddSwitch( 255 uint32_t selector_id, uint32_t default_id, 256 const std::vector<std::pair<Operand::OperandData, uint32_t>>& targets, 257 uint32_t merge_id = kInvalidId, 258 uint32_t selection_control = SpvSelectionControlMaskNone) { 259 if (merge_id != kInvalidId) { 260 AddSelectionMerge(merge_id, selection_control); 261 } 262 std::vector<Operand> operands; 263 operands.emplace_back( 264 Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {selector_id}}); 265 operands.emplace_back( 266 Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {default_id}}); 267 for (auto& target : targets) { 268 operands.emplace_back( 269 Operand{spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, 270 target.first}); 271 operands.emplace_back( 272 Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {target.second}}); 273 } 274 std::unique_ptr<Instruction> new_switch( 275 new Instruction(GetContext(), SpvOpSwitch, 0, 0, operands)); 276 return AddInstruction(std::move(new_switch)); 277 } 278 279 // Creates a phi instruction. 280 // The id |type| must be the id of the phi instruction's type. 281 // The vector |incomings| must be a sequence of pairs of <definition id, 282 // parent id>. 283 Instruction* AddPhi(uint32_t type, const std::vector<uint32_t>& incomings, 284 uint32_t result = 0) { 285 assert(incomings.size() % 2 == 0 && "A sequence of pairs is expected"); 286 return AddNaryOp(type, SpvOpPhi, incomings, result); 287 } 288 289 // Creates an addition instruction. 290 // The id |type| must be the id of the instruction's type, must be the same as 291 // |op1| and |op2| types. 292 // The id |op1| is the left hand side of the operation. 293 // The id |op2| is the right hand side of the operation. AddIAdd(uint32_t type,uint32_t op1,uint32_t op2)294 Instruction* AddIAdd(uint32_t type, uint32_t op1, uint32_t op2) { 295 // TODO(1841): Handle id overflow. 296 std::unique_ptr<Instruction> inst(new Instruction( 297 GetContext(), SpvOpIAdd, type, GetContext()->TakeNextId(), 298 {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}})); 299 return AddInstruction(std::move(inst)); 300 } 301 302 // Creates a less than instruction for unsigned integer. 303 // The id |op1| is the left hand side of the operation. 304 // The id |op2| is the right hand side of the operation. 305 // It is assumed that |op1| and |op2| have the same underlying type. AddULessThan(uint32_t op1,uint32_t op2)306 Instruction* AddULessThan(uint32_t op1, uint32_t op2) { 307 analysis::Bool bool_type; 308 uint32_t type = GetContext()->get_type_mgr()->GetId(&bool_type); 309 // TODO(1841): Handle id overflow. 310 std::unique_ptr<Instruction> inst(new Instruction( 311 GetContext(), SpvOpULessThan, type, GetContext()->TakeNextId(), 312 {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}})); 313 return AddInstruction(std::move(inst)); 314 } 315 316 // Creates a less than instruction for signed integer. 317 // The id |op1| is the left hand side of the operation. 318 // The id |op2| is the right hand side of the operation. 319 // It is assumed that |op1| and |op2| have the same underlying type. AddSLessThan(uint32_t op1,uint32_t op2)320 Instruction* AddSLessThan(uint32_t op1, uint32_t op2) { 321 analysis::Bool bool_type; 322 uint32_t type = GetContext()->get_type_mgr()->GetId(&bool_type); 323 // TODO(1841): Handle id overflow. 324 std::unique_ptr<Instruction> inst(new Instruction( 325 GetContext(), SpvOpSLessThan, type, GetContext()->TakeNextId(), 326 {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}})); 327 return AddInstruction(std::move(inst)); 328 } 329 330 // Creates an OpILessThan or OpULessThen instruction depending on the sign of 331 // |op1|. The id |op1| is the left hand side of the operation. The id |op2| is 332 // the right hand side of the operation. It is assumed that |op1| and |op2| 333 // have the same underlying type. AddLessThan(uint32_t op1,uint32_t op2)334 Instruction* AddLessThan(uint32_t op1, uint32_t op2) { 335 Instruction* op1_insn = context_->get_def_use_mgr()->GetDef(op1); 336 analysis::Type* type = 337 GetContext()->get_type_mgr()->GetType(op1_insn->type_id()); 338 analysis::Integer* int_type = type->AsInteger(); 339 assert(int_type && "Operand is not of int type"); 340 341 if (int_type->IsSigned()) 342 return AddSLessThan(op1, op2); 343 else 344 return AddULessThan(op1, op2); 345 } 346 347 // Creates a select instruction. 348 // |type| must match the types of |true_value| and |false_value|. It is up to 349 // the caller to ensure that |cond| is a correct type (bool or vector of 350 // bool) for |type|. AddSelect(uint32_t type,uint32_t cond,uint32_t true_value,uint32_t false_value)351 Instruction* AddSelect(uint32_t type, uint32_t cond, uint32_t true_value, 352 uint32_t false_value) { 353 // TODO(1841): Handle id overflow. 354 std::unique_ptr<Instruction> select(new Instruction( 355 GetContext(), SpvOpSelect, type, GetContext()->TakeNextId(), 356 std::initializer_list<Operand>{{SPV_OPERAND_TYPE_ID, {cond}}, 357 {SPV_OPERAND_TYPE_ID, {true_value}}, 358 {SPV_OPERAND_TYPE_ID, {false_value}}})); 359 return AddInstruction(std::move(select)); 360 } 361 362 // Adds a signed int32 constant to the binary. 363 // The |value| parameter is the constant value to be added. GetSintConstant(int32_t value)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|. AddCompositeConstruct(uint32_t type,const std::vector<uint32_t> & 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. GetUintConstant(uint32_t value)386 Instruction* GetUintConstant(uint32_t value) { 387 return GetIntConstant<uint32_t>(value, false); 388 } 389 GetUintConstantId(uint32_t value)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> GetIntConstant(T value,bool sign)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 AddCompositeExtract(uint32_t type,uint32_t id_of_composite,const std::vector<uint32_t> & index_list)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. AddUnreachable()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 AddAccessChain(uint32_t type_id,uint32_t base_ptr_id,std::vector<uint32_t> ids)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 AddLoad(uint32_t type_id,uint32_t base_ptr_id)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 AddStore(uint32_t ptr_id,uint32_t obj_id)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 AddFunctionCall(uint32_t result_type,uint32_t function,const std::vector<uint32_t> & parameters)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 AddVectorShuffle(uint32_t result_type,uint32_t vec1,uint32_t vec2,const std::vector<uint32_t> & components)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 AddNaryExtendedInstruction(uint32_t result_type,uint32_t set,uint32_t instruction,const std::vector<uint32_t> & ext_operands)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. AddInstruction(std::unique_ptr<Instruction> && insn)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. GetInsertPoint()559 InsertionPointTy GetInsertPoint() { return insert_before_; } 560 561 // Change the insertion point to insert before the instruction 562 // |insert_before|. SetInsertPoint(Instruction * 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|. SetInsertPoint(BasicBlock * 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. GetContext()576 IRContext* GetContext() const { return context_; } 577 578 // Returns the set of preserved analyses. GetPreservedAnalysis()579 inline IRContext::Analysis GetPreservedAnalysis() const { 580 return preserved_analyses_; 581 } 582 583 private: InstructionBuilder(IRContext * context,BasicBlock * parent,InsertionPointTy insert_before,IRContext::Analysis preserved_analyses)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|. IsAnalysisUpdateRequested(IRContext::Analysis 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 an update was not 605 // requested, this function does nothing. UpdateDefUseMgr(Instruction * insn)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 612 // an update was not requested, this function does nothing. UpdateInstrToBlockMapping(Instruction * insn)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