1 // Copyright (c) 2016 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 #include "source/opt/ir_loader.h" 16 17 #include <utility> 18 19 #include "source/opt/log.h" 20 #include "source/opt/reflect.h" 21 #include "source/util/make_unique.h" 22 23 namespace spvtools { 24 namespace opt { 25 26 IrLoader::IrLoader(const MessageConsumer& consumer, Module* m) 27 : consumer_(consumer), 28 module_(m), 29 source_("<instruction>"), 30 inst_index_(0) {} 31 32 bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { 33 ++inst_index_; 34 const auto opcode = static_cast<SpvOp>(inst->opcode); 35 if (IsDebugLineInst(opcode)) { 36 dbg_line_info_.push_back(Instruction(module()->context(), *inst)); 37 return true; 38 } 39 40 std::unique_ptr<Instruction> spv_inst( 41 new Instruction(module()->context(), *inst, std::move(dbg_line_info_))); 42 dbg_line_info_.clear(); 43 44 const char* src = source_.c_str(); 45 spv_position_t loc = {inst_index_, 0, 0}; 46 47 // Handle function and basic block boundaries first, then normal 48 // instructions. 49 if (opcode == SpvOpFunction) { 50 if (function_ != nullptr) { 51 Error(consumer_, src, loc, "function inside function"); 52 return false; 53 } 54 function_ = MakeUnique<Function>(std::move(spv_inst)); 55 } else if (opcode == SpvOpFunctionEnd) { 56 if (function_ == nullptr) { 57 Error(consumer_, src, loc, 58 "OpFunctionEnd without corresponding OpFunction"); 59 return false; 60 } 61 if (block_ != nullptr) { 62 Error(consumer_, src, loc, "OpFunctionEnd inside basic block"); 63 return false; 64 } 65 function_->SetFunctionEnd(std::move(spv_inst)); 66 module_->AddFunction(std::move(function_)); 67 function_ = nullptr; 68 } else if (opcode == SpvOpLabel) { 69 if (function_ == nullptr) { 70 Error(consumer_, src, loc, "OpLabel outside function"); 71 return false; 72 } 73 if (block_ != nullptr) { 74 Error(consumer_, src, loc, "OpLabel inside basic block"); 75 return false; 76 } 77 block_ = MakeUnique<BasicBlock>(std::move(spv_inst)); 78 } else if (IsTerminatorInst(opcode)) { 79 if (function_ == nullptr) { 80 Error(consumer_, src, loc, "terminator instruction outside function"); 81 return false; 82 } 83 if (block_ == nullptr) { 84 Error(consumer_, src, loc, "terminator instruction outside basic block"); 85 return false; 86 } 87 block_->AddInstruction(std::move(spv_inst)); 88 function_->AddBasicBlock(std::move(block_)); 89 block_ = nullptr; 90 } else { 91 if (function_ == nullptr) { // Outside function definition 92 SPIRV_ASSERT(consumer_, block_ == nullptr); 93 if (opcode == SpvOpCapability) { 94 module_->AddCapability(std::move(spv_inst)); 95 } else if (opcode == SpvOpExtension) { 96 module_->AddExtension(std::move(spv_inst)); 97 } else if (opcode == SpvOpExtInstImport) { 98 module_->AddExtInstImport(std::move(spv_inst)); 99 } else if (opcode == SpvOpMemoryModel) { 100 module_->SetMemoryModel(std::move(spv_inst)); 101 } else if (opcode == SpvOpEntryPoint) { 102 module_->AddEntryPoint(std::move(spv_inst)); 103 } else if (opcode == SpvOpExecutionMode) { 104 module_->AddExecutionMode(std::move(spv_inst)); 105 } else if (IsDebug1Inst(opcode)) { 106 module_->AddDebug1Inst(std::move(spv_inst)); 107 } else if (IsDebug2Inst(opcode)) { 108 module_->AddDebug2Inst(std::move(spv_inst)); 109 } else if (IsDebug3Inst(opcode)) { 110 module_->AddDebug3Inst(std::move(spv_inst)); 111 } else if (IsAnnotationInst(opcode)) { 112 module_->AddAnnotationInst(std::move(spv_inst)); 113 } else if (IsTypeInst(opcode)) { 114 module_->AddType(std::move(spv_inst)); 115 } else if (IsConstantInst(opcode) || opcode == SpvOpVariable || 116 opcode == SpvOpUndef) { 117 module_->AddGlobalValue(std::move(spv_inst)); 118 } else { 119 SPIRV_UNIMPLEMENTED(consumer_, 120 "unhandled inst type outside function definition"); 121 } 122 } else { 123 if (block_ == nullptr) { // Inside function but outside blocks 124 if (opcode != SpvOpFunctionParameter) { 125 Errorf(consumer_, src, loc, 126 "Non-OpFunctionParameter (opcode: %d) found inside " 127 "function but outside basic block", 128 opcode); 129 return false; 130 } 131 function_->AddParameter(std::move(spv_inst)); 132 } else { 133 block_->AddInstruction(std::move(spv_inst)); 134 } 135 } 136 } 137 return true; 138 } 139 140 // Resolves internal references among the module, functions, basic blocks, etc. 141 // This function should be called after adding all instructions. 142 void IrLoader::EndModule() { 143 if (block_ && function_) { 144 // We're in the middle of a basic block, but the terminator is missing. 145 // Register the block anyway. This lets us write tests with less 146 // boilerplate. 147 function_->AddBasicBlock(std::move(block_)); 148 block_ = nullptr; 149 } 150 if (function_) { 151 // We're in the middle of a function, but the OpFunctionEnd is missing. 152 // Register the function anyway. This lets us write tests with less 153 // boilerplate. 154 module_->AddFunction(std::move(function_)); 155 function_ = nullptr; 156 } 157 for (auto& function : *module_) { 158 for (auto& bb : function) bb.SetParent(&function); 159 } 160 } 161 162 } // namespace opt 163 } // namespace spvtools 164