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 // TODO(1841): Handle id overflow. 63 std::unique_ptr<Instruction> newUnOp(new Instruction( 64 GetContext(), opcode, type_id, 65 opcode == SpvOpReturn ? 0 : GetContext()->TakeNextId(), {})); 66 return AddInstruction(std::move(newUnOp)); 67 } 68 AddUnaryOp(uint32_t type_id,SpvOp opcode,uint32_t operand1)69 Instruction* AddUnaryOp(uint32_t type_id, SpvOp opcode, uint32_t operand1) { 70 // TODO(1841): Handle id overflow. 71 std::unique_ptr<Instruction> newUnOp(new Instruction( 72 GetContext(), opcode, type_id, GetContext()->TakeNextId(), 73 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}})); 74 return AddInstruction(std::move(newUnOp)); 75 } 76 AddBinaryOp(uint32_t type_id,SpvOp opcode,uint32_t operand1,uint32_t operand2)77 Instruction* AddBinaryOp(uint32_t type_id, SpvOp opcode, uint32_t operand1, 78 uint32_t operand2) { 79 // TODO(1841): Handle id overflow. 80 std::unique_ptr<Instruction> newBinOp(new Instruction( 81 GetContext(), opcode, type_id, 82 opcode == SpvOpStore ? 0 : GetContext()->TakeNextId(), 83 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}, 84 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}}})); 85 return AddInstruction(std::move(newBinOp)); 86 } 87 AddTernaryOp(uint32_t type_id,SpvOp opcode,uint32_t operand1,uint32_t operand2,uint32_t operand3)88 Instruction* AddTernaryOp(uint32_t type_id, SpvOp opcode, uint32_t operand1, 89 uint32_t operand2, uint32_t operand3) { 90 // TODO(1841): Handle id overflow. 91 std::unique_ptr<Instruction> newTernOp(new Instruction( 92 GetContext(), opcode, type_id, GetContext()->TakeNextId(), 93 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}, 94 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}}, 95 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand3}}})); 96 return AddInstruction(std::move(newTernOp)); 97 } 98 AddQuadOp(uint32_t type_id,SpvOp opcode,uint32_t operand1,uint32_t operand2,uint32_t operand3,uint32_t operand4)99 Instruction* AddQuadOp(uint32_t type_id, SpvOp opcode, uint32_t operand1, 100 uint32_t operand2, uint32_t operand3, 101 uint32_t operand4) { 102 // TODO(1841): Handle id overflow. 103 std::unique_ptr<Instruction> newQuadOp(new Instruction( 104 GetContext(), opcode, type_id, GetContext()->TakeNextId(), 105 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}, 106 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}}, 107 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand3}}, 108 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand4}}})); 109 return AddInstruction(std::move(newQuadOp)); 110 } 111 AddIdLiteralOp(uint32_t type_id,SpvOp opcode,uint32_t operand1,uint32_t operand2)112 Instruction* AddIdLiteralOp(uint32_t type_id, SpvOp opcode, uint32_t operand1, 113 uint32_t operand2) { 114 // TODO(1841): Handle id overflow. 115 std::unique_ptr<Instruction> newBinOp(new Instruction( 116 GetContext(), opcode, type_id, GetContext()->TakeNextId(), 117 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}, 118 {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {operand2}}})); 119 return AddInstruction(std::move(newBinOp)); 120 } 121 122 // Creates an N-ary instruction of |opcode|. 123 // |typid| must be the id of the instruction's type. 124 // |operands| must be a sequence of operand ids. 125 // Use |result| for the result id if non-zero. 126 Instruction* AddNaryOp(uint32_t type_id, SpvOp opcode, 127 const std::vector<uint32_t>& operands, 128 uint32_t result = 0) { 129 std::vector<Operand> ops; 130 for (size_t i = 0; i < operands.size(); i++) { 131 ops.push_back({SPV_OPERAND_TYPE_ID, {operands[i]}}); 132 } 133 // TODO(1841): Handle id overflow. 134 std::unique_ptr<Instruction> new_inst(new Instruction( 135 GetContext(), opcode, type_id, 136 result != 0 ? result : GetContext()->TakeNextId(), ops)); 137 return AddInstruction(std::move(new_inst)); 138 } 139 140 // Creates a new selection merge instruction. 141 // The id |merge_id| is the merge basic block id. 142 Instruction* AddSelectionMerge( 143 uint32_t merge_id, 144 uint32_t selection_control = SpvSelectionControlMaskNone) { 145 std::unique_ptr<Instruction> new_branch_merge(new Instruction( 146 GetContext(), SpvOpSelectionMerge, 0, 0, 147 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}}, 148 {spv_operand_type_t::SPV_OPERAND_TYPE_SELECTION_CONTROL, 149 {selection_control}}})); 150 return AddInstruction(std::move(new_branch_merge)); 151 } 152 153 // Creates a new loop merge instruction. 154 // The id |merge_id| is the basic block id of the merge block. 155 // |continue_id| is the id of the continue block. 156 // |loop_control| are the loop control flags to be added to the instruction. 157 Instruction* AddLoopMerge(uint32_t merge_id, uint32_t continue_id, 158 uint32_t loop_control = SpvLoopControlMaskNone) { 159 std::unique_ptr<Instruction> new_branch_merge(new Instruction( 160 GetContext(), SpvOpLoopMerge, 0, 0, 161 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}}, 162 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {continue_id}}, 163 {spv_operand_type_t::SPV_OPERAND_TYPE_LOOP_CONTROL, {loop_control}}})); 164 return AddInstruction(std::move(new_branch_merge)); 165 } 166 167 // Creates a new branch instruction to |label_id|. 168 // Note that the user must make sure the final basic block is 169 // well formed. AddBranch(uint32_t label_id)170 Instruction* AddBranch(uint32_t label_id) { 171 std::unique_ptr<Instruction> new_branch(new Instruction( 172 GetContext(), SpvOpBranch, 0, 0, 173 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {label_id}}})); 174 return AddInstruction(std::move(new_branch)); 175 } 176 177 // Creates a new conditional instruction and the associated selection merge 178 // instruction if requested. 179 // The id |cond_id| is the id of the condition instruction, must be of 180 // type bool. 181 // The id |true_id| is the id of the basic block to branch to if the condition 182 // is true. 183 // The id |false_id| is the id of the basic block to branch to if the 184 // condition is false. 185 // The id |merge_id| is the id of the merge basic block for the selection 186 // merge instruction. If |merge_id| equals kInvalidId then no selection merge 187 // instruction will be created. 188 // The value |selection_control| is the selection control flag for the 189 // selection merge instruction. 190 // Note that the user must make sure the final basic block is 191 // well formed. 192 Instruction* AddConditionalBranch( 193 uint32_t cond_id, uint32_t true_id, uint32_t false_id, 194 uint32_t merge_id = kInvalidId, 195 uint32_t selection_control = SpvSelectionControlMaskNone) { 196 if (merge_id != kInvalidId) { 197 AddSelectionMerge(merge_id, selection_control); 198 } 199 std::unique_ptr<Instruction> new_branch(new Instruction( 200 GetContext(), SpvOpBranchConditional, 0, 0, 201 {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {cond_id}}, 202 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {true_id}}, 203 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {false_id}}})); 204 return AddInstruction(std::move(new_branch)); 205 } 206 207 // Creates a new switch instruction and the associated selection merge 208 // instruction if requested. 209 // The id |selector_id| is the id of the selector instruction, must be of 210 // type int. 211 // The id |default_id| is the id of the default basic block to branch to. 212 // The vector |targets| is the pair of literal/branch id. 213 // The id |merge_id| is the id of the merge basic block for the selection 214 // merge instruction. If |merge_id| equals kInvalidId then no selection merge 215 // instruction will be created. 216 // The value |selection_control| is the selection control flag for the 217 // selection merge instruction. 218 // Note that the user must make sure the final basic block is 219 // well formed. 220 Instruction* AddSwitch( 221 uint32_t selector_id, uint32_t default_id, 222 const std::vector<std::pair<Operand::OperandData, uint32_t>>& targets, 223 uint32_t merge_id = kInvalidId, 224 uint32_t selection_control = SpvSelectionControlMaskNone) { 225 if (merge_id != kInvalidId) { 226 AddSelectionMerge(merge_id, selection_control); 227 } 228 std::vector<Operand> operands; 229 operands.emplace_back( 230 Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {selector_id}}); 231 operands.emplace_back( 232 Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {default_id}}); 233 for (auto& target : targets) { 234 operands.emplace_back( 235 Operand{spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, 236 target.first}); 237 operands.emplace_back( 238 Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {target.second}}); 239 } 240 std::unique_ptr<Instruction> new_switch( 241 new Instruction(GetContext(), SpvOpSwitch, 0, 0, operands)); 242 return AddInstruction(std::move(new_switch)); 243 } 244 245 // Creates a phi instruction. 246 // The id |type| must be the id of the phi instruction's type. 247 // The vector |incomings| must be a sequence of pairs of <definition id, 248 // parent id>. 249 Instruction* AddPhi(uint32_t type, const std::vector<uint32_t>& incomings, 250 uint32_t result = 0) { 251 assert(incomings.size() % 2 == 0 && "A sequence of pairs is expected"); 252 return AddNaryOp(type, SpvOpPhi, incomings, result); 253 } 254 255 // Creates an addition instruction. 256 // The id |type| must be the id of the instruction's type, must be the same as 257 // |op1| and |op2| types. 258 // The id |op1| is the left hand side of the operation. 259 // The id |op2| is the right hand side of the operation. AddIAdd(uint32_t type,uint32_t op1,uint32_t op2)260 Instruction* AddIAdd(uint32_t type, uint32_t op1, uint32_t op2) { 261 // TODO(1841): Handle id overflow. 262 std::unique_ptr<Instruction> inst(new Instruction( 263 GetContext(), SpvOpIAdd, type, GetContext()->TakeNextId(), 264 {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}})); 265 return AddInstruction(std::move(inst)); 266 } 267 268 // Creates a less than instruction for unsigned integer. 269 // The id |op1| is the left hand side of the operation. 270 // The id |op2| is the right hand side of the operation. 271 // It is assumed that |op1| and |op2| have the same underlying type. AddULessThan(uint32_t op1,uint32_t op2)272 Instruction* AddULessThan(uint32_t op1, uint32_t op2) { 273 analysis::Bool bool_type; 274 uint32_t type = GetContext()->get_type_mgr()->GetId(&bool_type); 275 // TODO(1841): Handle id overflow. 276 std::unique_ptr<Instruction> inst(new Instruction( 277 GetContext(), SpvOpULessThan, type, GetContext()->TakeNextId(), 278 {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}})); 279 return AddInstruction(std::move(inst)); 280 } 281 282 // Creates a less than instruction for signed integer. 283 // The id |op1| is the left hand side of the operation. 284 // The id |op2| is the right hand side of the operation. 285 // It is assumed that |op1| and |op2| have the same underlying type. AddSLessThan(uint32_t op1,uint32_t op2)286 Instruction* AddSLessThan(uint32_t op1, uint32_t op2) { 287 analysis::Bool bool_type; 288 uint32_t type = GetContext()->get_type_mgr()->GetId(&bool_type); 289 // TODO(1841): Handle id overflow. 290 std::unique_ptr<Instruction> inst(new Instruction( 291 GetContext(), SpvOpSLessThan, type, GetContext()->TakeNextId(), 292 {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}})); 293 return AddInstruction(std::move(inst)); 294 } 295 296 // Creates an OpILessThan or OpULessThen instruction depending on the sign of 297 // |op1|. The id |op1| is the left hand side of the operation. The id |op2| is 298 // the right hand side of the operation. It is assumed that |op1| and |op2| 299 // have the same underlying type. AddLessThan(uint32_t op1,uint32_t op2)300 Instruction* AddLessThan(uint32_t op1, uint32_t op2) { 301 Instruction* op1_insn = context_->get_def_use_mgr()->GetDef(op1); 302 analysis::Type* type = 303 GetContext()->get_type_mgr()->GetType(op1_insn->type_id()); 304 analysis::Integer* int_type = type->AsInteger(); 305 assert(int_type && "Operand is not of int type"); 306 307 if (int_type->IsSigned()) 308 return AddSLessThan(op1, op2); 309 else 310 return AddULessThan(op1, op2); 311 } 312 313 // Creates a select instruction. 314 // |type| must match the types of |true_value| and |false_value|. It is up to 315 // the caller to ensure that |cond| is a correct type (bool or vector of 316 // bool) for |type|. AddSelect(uint32_t type,uint32_t cond,uint32_t true_value,uint32_t false_value)317 Instruction* AddSelect(uint32_t type, uint32_t cond, uint32_t true_value, 318 uint32_t false_value) { 319 // TODO(1841): Handle id overflow. 320 std::unique_ptr<Instruction> select(new Instruction( 321 GetContext(), SpvOpSelect, type, GetContext()->TakeNextId(), 322 std::initializer_list<Operand>{{SPV_OPERAND_TYPE_ID, {cond}}, 323 {SPV_OPERAND_TYPE_ID, {true_value}}, 324 {SPV_OPERAND_TYPE_ID, {false_value}}})); 325 return AddInstruction(std::move(select)); 326 } 327 328 // Adds a signed int32 constant to the binary. 329 // The |value| parameter is the constant value to be added. GetSintConstant(int32_t value)330 Instruction* GetSintConstant(int32_t value) { 331 return GetIntConstant<int32_t>(value, true); 332 } 333 334 // Create a composite construct. 335 // |type| should be a composite type and the number of elements it has should 336 // match the size od |ids|. AddCompositeConstruct(uint32_t type,const std::vector<uint32_t> & ids)337 Instruction* AddCompositeConstruct(uint32_t type, 338 const std::vector<uint32_t>& ids) { 339 std::vector<Operand> ops; 340 for (auto id : ids) { 341 ops.emplace_back(SPV_OPERAND_TYPE_ID, 342 std::initializer_list<uint32_t>{id}); 343 } 344 // TODO(1841): Handle id overflow. 345 std::unique_ptr<Instruction> construct( 346 new Instruction(GetContext(), SpvOpCompositeConstruct, type, 347 GetContext()->TakeNextId(), ops)); 348 return AddInstruction(std::move(construct)); 349 } 350 // Adds an unsigned int32 constant to the binary. 351 // The |value| parameter is the constant value to be added. GetUintConstant(uint32_t value)352 Instruction* GetUintConstant(uint32_t value) { 353 return GetIntConstant<uint32_t>(value, false); 354 } 355 GetUintConstantId(uint32_t value)356 uint32_t GetUintConstantId(uint32_t value) { 357 Instruction* uint_inst = GetUintConstant(value); 358 return uint_inst->result_id(); 359 } 360 GetNullId(uint32_t type_id)361 uint32_t GetNullId(uint32_t type_id) { 362 analysis::TypeManager* type_mgr = GetContext()->get_type_mgr(); 363 analysis::ConstantManager* const_mgr = GetContext()->get_constant_mgr(); 364 const analysis::Type* type = type_mgr->GetType(type_id); 365 const analysis::Constant* null_const = const_mgr->GetConstant(type, {}); 366 Instruction* null_inst = 367 const_mgr->GetDefiningInstruction(null_const, type_id); 368 return null_inst->result_id(); 369 } 370 371 // Adds either a signed or unsigned 32 bit integer constant to the binary 372 // depedning on the |sign|. If |sign| is true then the value is added as a 373 // signed constant otherwise as an unsigned constant. If |sign| is false the 374 // value must not be a negative number. 375 template <typename T> GetIntConstant(T value,bool sign)376 Instruction* GetIntConstant(T value, bool sign) { 377 // Assert that we are not trying to store a negative number in an unsigned 378 // type. 379 if (!sign) 380 assert(value >= 0 && 381 "Trying to add a signed integer with an unsigned type!"); 382 383 analysis::Integer int_type{32, sign}; 384 385 // Get or create the integer type. This rebuilds the type and manages the 386 // memory for the rebuilt type. 387 uint32_t type_id = 388 GetContext()->get_type_mgr()->GetTypeInstruction(&int_type); 389 390 // Get the memory managed type so that it is safe to be stored by 391 // GetConstant. 392 analysis::Type* rebuilt_type = 393 GetContext()->get_type_mgr()->GetType(type_id); 394 395 // Even if the value is negative we need to pass the bit pattern as a 396 // uint32_t to GetConstant. 397 uint32_t word = value; 398 399 // Create the constant value. 400 const analysis::Constant* constant = 401 GetContext()->get_constant_mgr()->GetConstant(rebuilt_type, {word}); 402 403 // Create the OpConstant instruction using the type and the value. 404 return GetContext()->get_constant_mgr()->GetDefiningInstruction(constant); 405 } 406 AddCompositeExtract(uint32_t type,uint32_t id_of_composite,const std::vector<uint32_t> & index_list)407 Instruction* AddCompositeExtract(uint32_t type, uint32_t id_of_composite, 408 const std::vector<uint32_t>& index_list) { 409 std::vector<Operand> operands; 410 operands.push_back({SPV_OPERAND_TYPE_ID, {id_of_composite}}); 411 412 for (uint32_t index : index_list) { 413 operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {index}}); 414 } 415 416 // TODO(1841): Handle id overflow. 417 std::unique_ptr<Instruction> new_inst( 418 new Instruction(GetContext(), SpvOpCompositeExtract, type, 419 GetContext()->TakeNextId(), operands)); 420 return AddInstruction(std::move(new_inst)); 421 } 422 423 // Creates an unreachable instruction. AddUnreachable()424 Instruction* AddUnreachable() { 425 std::unique_ptr<Instruction> select( 426 new Instruction(GetContext(), SpvOpUnreachable, 0, 0, 427 std::initializer_list<Operand>{})); 428 return AddInstruction(std::move(select)); 429 } 430 AddAccessChain(uint32_t type_id,uint32_t base_ptr_id,std::vector<uint32_t> ids)431 Instruction* AddAccessChain(uint32_t type_id, uint32_t base_ptr_id, 432 std::vector<uint32_t> ids) { 433 std::vector<Operand> operands; 434 operands.push_back({SPV_OPERAND_TYPE_ID, {base_ptr_id}}); 435 436 for (uint32_t index_id : ids) { 437 operands.push_back({SPV_OPERAND_TYPE_ID, {index_id}}); 438 } 439 440 // TODO(1841): Handle id overflow. 441 std::unique_ptr<Instruction> new_inst( 442 new Instruction(GetContext(), SpvOpAccessChain, type_id, 443 GetContext()->TakeNextId(), operands)); 444 return AddInstruction(std::move(new_inst)); 445 } 446 AddLoad(uint32_t type_id,uint32_t base_ptr_id)447 Instruction* AddLoad(uint32_t type_id, uint32_t base_ptr_id) { 448 std::vector<Operand> operands; 449 operands.push_back({SPV_OPERAND_TYPE_ID, {base_ptr_id}}); 450 451 // TODO(1841): Handle id overflow. 452 std::unique_ptr<Instruction> new_inst( 453 new Instruction(GetContext(), SpvOpLoad, type_id, 454 GetContext()->TakeNextId(), operands)); 455 return AddInstruction(std::move(new_inst)); 456 } 457 458 // Inserts the new instruction before the insertion point. AddInstruction(std::unique_ptr<Instruction> && insn)459 Instruction* AddInstruction(std::unique_ptr<Instruction>&& insn) { 460 Instruction* insn_ptr = &*insert_before_.InsertBefore(std::move(insn)); 461 UpdateInstrToBlockMapping(insn_ptr); 462 UpdateDefUseMgr(insn_ptr); 463 return insn_ptr; 464 } 465 466 // Returns the insertion point iterator. GetInsertPoint()467 InsertionPointTy GetInsertPoint() { return insert_before_; } 468 469 // Change the insertion point to insert before the instruction 470 // |insert_before|. SetInsertPoint(Instruction * insert_before)471 void SetInsertPoint(Instruction* insert_before) { 472 parent_ = context_->get_instr_block(insert_before); 473 insert_before_ = InsertionPointTy(insert_before); 474 } 475 476 // Change the insertion point to insert at the end of the basic block 477 // |parent_block|. SetInsertPoint(BasicBlock * parent_block)478 void SetInsertPoint(BasicBlock* parent_block) { 479 parent_ = parent_block; 480 insert_before_ = parent_block->end(); 481 } 482 483 // Returns the context which instructions are constructed for. GetContext()484 IRContext* GetContext() const { return context_; } 485 486 // Returns the set of preserved analyses. GetPreservedAnalysis()487 inline IRContext::Analysis GetPreservedAnalysis() const { 488 return preserved_analyses_; 489 } 490 491 private: InstructionBuilder(IRContext * context,BasicBlock * parent,InsertionPointTy insert_before,IRContext::Analysis preserved_analyses)492 InstructionBuilder(IRContext* context, BasicBlock* parent, 493 InsertionPointTy insert_before, 494 IRContext::Analysis preserved_analyses) 495 : context_(context), 496 parent_(parent), 497 insert_before_(insert_before), 498 preserved_analyses_(preserved_analyses) { 499 assert(!(preserved_analyses_ & ~(IRContext::kAnalysisDefUse | 500 IRContext::kAnalysisInstrToBlockMapping))); 501 } 502 503 // Returns true if the users requested to update |analysis|. IsAnalysisUpdateRequested(IRContext::Analysis analysis)504 inline bool IsAnalysisUpdateRequested(IRContext::Analysis analysis) const { 505 return preserved_analyses_ & analysis; 506 } 507 508 // Updates the def/use manager if the user requested it. If he did not request 509 // an update, this function does nothing. UpdateDefUseMgr(Instruction * insn)510 inline void UpdateDefUseMgr(Instruction* insn) { 511 if (IsAnalysisUpdateRequested(IRContext::kAnalysisDefUse)) 512 GetContext()->get_def_use_mgr()->AnalyzeInstDefUse(insn); 513 } 514 515 // Updates the instruction to block analysis if the user requested it. If he 516 // did not request an update, this function does nothing. UpdateInstrToBlockMapping(Instruction * insn)517 inline void UpdateInstrToBlockMapping(Instruction* insn) { 518 if (IsAnalysisUpdateRequested(IRContext::kAnalysisInstrToBlockMapping) && 519 parent_) 520 GetContext()->set_instr_block(insn, parent_); 521 } 522 523 IRContext* context_; 524 BasicBlock* parent_; 525 InsertionPointTy insert_before_; 526 const IRContext::Analysis preserved_analyses_; 527 }; 528 529 } // namespace opt 530 } // namespace spvtools 531 532 #endif // SOURCE_OPT_IR_BUILDER_H_ 533