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