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/module.h" 16 17 #include <algorithm> 18 #include <cstring> 19 #include <ostream> 20 21 #include "source/operand.h" 22 #include "source/opt/ir_context.h" 23 #include "source/opt/reflect.h" 24 25 namespace spvtools { 26 namespace opt { 27 28 uint32_t Module::TakeNextIdBound() { 29 if (context()) { 30 if (id_bound() >= context()->max_id_bound()) { 31 return 0; 32 } 33 } else if (id_bound() >= kDefaultMaxIdBound) { 34 return 0; 35 } 36 37 return header_.bound++; 38 } 39 40 std::vector<Instruction*> Module::GetTypes() { 41 std::vector<Instruction*> type_insts; 42 for (auto& inst : types_values_) { 43 if (IsTypeInst(inst.opcode())) type_insts.push_back(&inst); 44 } 45 return type_insts; 46 } 47 48 std::vector<const Instruction*> Module::GetTypes() const { 49 std::vector<const Instruction*> type_insts; 50 for (auto& inst : types_values_) { 51 if (IsTypeInst(inst.opcode())) type_insts.push_back(&inst); 52 } 53 return type_insts; 54 } 55 56 std::vector<Instruction*> Module::GetConstants() { 57 std::vector<Instruction*> const_insts; 58 for (auto& inst : types_values_) { 59 if (IsConstantInst(inst.opcode())) const_insts.push_back(&inst); 60 } 61 return const_insts; 62 } 63 64 std::vector<const Instruction*> Module::GetConstants() const { 65 std::vector<const Instruction*> const_insts; 66 for (auto& inst : types_values_) { 67 if (IsConstantInst(inst.opcode())) const_insts.push_back(&inst); 68 } 69 return const_insts; 70 } 71 72 uint32_t Module::GetGlobalValue(SpvOp opcode) const { 73 for (auto& inst : types_values_) { 74 if (inst.opcode() == opcode) return inst.result_id(); 75 } 76 return 0; 77 } 78 79 void Module::AddGlobalValue(SpvOp opcode, uint32_t result_id, 80 uint32_t type_id) { 81 std::unique_ptr<Instruction> newGlobal( 82 new Instruction(context(), opcode, type_id, result_id, {})); 83 AddGlobalValue(std::move(newGlobal)); 84 } 85 86 void Module::ForEachInst(const std::function<void(Instruction*)>& f, 87 bool run_on_debug_line_insts) { 88 #define DELEGATE(list) list.ForEachInst(f, run_on_debug_line_insts) 89 DELEGATE(capabilities_); 90 DELEGATE(extensions_); 91 DELEGATE(ext_inst_imports_); 92 if (memory_model_) memory_model_->ForEachInst(f, run_on_debug_line_insts); 93 DELEGATE(entry_points_); 94 DELEGATE(execution_modes_); 95 DELEGATE(debugs1_); 96 DELEGATE(debugs2_); 97 DELEGATE(debugs3_); 98 DELEGATE(annotations_); 99 DELEGATE(types_values_); 100 for (auto& i : functions_) i->ForEachInst(f, run_on_debug_line_insts); 101 #undef DELEGATE 102 } 103 104 void Module::ForEachInst(const std::function<void(const Instruction*)>& f, 105 bool run_on_debug_line_insts) const { 106 #define DELEGATE(i) i.ForEachInst(f, run_on_debug_line_insts) 107 for (auto& i : capabilities_) DELEGATE(i); 108 for (auto& i : extensions_) DELEGATE(i); 109 for (auto& i : ext_inst_imports_) DELEGATE(i); 110 if (memory_model_) 111 static_cast<const Instruction*>(memory_model_.get()) 112 ->ForEachInst(f, run_on_debug_line_insts); 113 for (auto& i : entry_points_) DELEGATE(i); 114 for (auto& i : execution_modes_) DELEGATE(i); 115 for (auto& i : debugs1_) DELEGATE(i); 116 for (auto& i : debugs2_) DELEGATE(i); 117 for (auto& i : debugs3_) DELEGATE(i); 118 for (auto& i : annotations_) DELEGATE(i); 119 for (auto& i : types_values_) DELEGATE(i); 120 for (auto& i : functions_) { 121 static_cast<const Function*>(i.get())->ForEachInst(f, 122 run_on_debug_line_insts); 123 } 124 #undef DELEGATE 125 } 126 127 void Module::ToBinary(std::vector<uint32_t>* binary, bool skip_nop) const { 128 binary->push_back(header_.magic_number); 129 binary->push_back(header_.version); 130 // TODO(antiagainst): should we change the generator number? 131 binary->push_back(header_.generator); 132 binary->push_back(header_.bound); 133 binary->push_back(header_.reserved); 134 135 auto write_inst = [binary, skip_nop](const Instruction* i) { 136 if (!(skip_nop && i->IsNop())) i->ToBinaryWithoutAttachedDebugInsts(binary); 137 }; 138 ForEachInst(write_inst, true); 139 } 140 141 uint32_t Module::ComputeIdBound() const { 142 uint32_t highest = 0; 143 144 ForEachInst( 145 [&highest](const Instruction* inst) { 146 for (const auto& operand : *inst) { 147 if (spvIsIdType(operand.type)) { 148 highest = std::max(highest, operand.words[0]); 149 } 150 } 151 }, 152 true /* scan debug line insts as well */); 153 154 return highest + 1; 155 } 156 157 bool Module::HasExplicitCapability(uint32_t cap) { 158 for (auto& ci : capabilities_) { 159 uint32_t tcap = ci.GetSingleWordOperand(0); 160 if (tcap == cap) { 161 return true; 162 } 163 } 164 return false; 165 } 166 167 uint32_t Module::GetExtInstImportId(const char* extstr) { 168 for (auto& ei : ext_inst_imports_) 169 if (!strcmp(extstr, 170 reinterpret_cast<const char*>(&(ei.GetInOperand(0).words[0])))) 171 return ei.result_id(); 172 return 0; 173 } 174 175 std::ostream& operator<<(std::ostream& str, const Module& module) { 176 module.ForEachInst([&str](const Instruction* inst) { 177 str << *inst; 178 if (inst->opcode() != SpvOpFunctionEnd) { 179 str << std::endl; 180 } 181 }); 182 return str; 183 } 184 185 } // namespace opt 186 } // namespace spvtools 187