• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "DebugInfo.h"
20 #include "OpenCLDebugInfo100.h"
21 #include "source/ext_inst.h"
22 #include "source/opt/log.h"
23 #include "source/opt/reflect.h"
24 #include "source/util/make_unique.h"
25 
26 static const uint32_t kExtInstSetIndex = 4;
27 static const uint32_t kLexicalScopeIndex = 5;
28 static const uint32_t kInlinedAtIndex = 6;
29 
30 namespace spvtools {
31 namespace opt {
32 
IrLoader(const MessageConsumer & consumer,Module * m)33 IrLoader::IrLoader(const MessageConsumer& consumer, Module* m)
34     : consumer_(consumer),
35       module_(m),
36       source_("<instruction>"),
37       inst_index_(0),
38       last_dbg_scope_(kNoDebugScope, kNoInlinedAt) {}
39 
AddInstruction(const spv_parsed_instruction_t * inst)40 bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
41   ++inst_index_;
42   const auto opcode = static_cast<SpvOp>(inst->opcode);
43   if (IsDebugLineInst(opcode)) {
44     dbg_line_info_.push_back(
45         Instruction(module()->context(), *inst, last_dbg_scope_));
46     return true;
47   }
48 
49   // If it is a DebugScope or DebugNoScope of debug extension, we do not
50   // create a new instruction, but simply keep the information in
51   // struct DebugScope.
52   if (opcode == SpvOpExtInst && spvExtInstIsDebugInfo(inst->ext_inst_type)) {
53     const uint32_t ext_inst_index = inst->words[kExtInstSetIndex];
54     if (inst->ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
55       const OpenCLDebugInfo100Instructions ext_inst_key =
56           OpenCLDebugInfo100Instructions(ext_inst_index);
57       if (ext_inst_key == OpenCLDebugInfo100DebugScope) {
58         uint32_t inlined_at = 0;
59         if (inst->num_words > kInlinedAtIndex)
60           inlined_at = inst->words[kInlinedAtIndex];
61         last_dbg_scope_ =
62             DebugScope(inst->words[kLexicalScopeIndex], inlined_at);
63         module()->SetContainsDebugScope();
64         return true;
65       }
66       if (ext_inst_key == OpenCLDebugInfo100DebugNoScope) {
67         last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt);
68         module()->SetContainsDebugScope();
69         return true;
70       }
71     } else {
72       const DebugInfoInstructions ext_inst_key =
73           DebugInfoInstructions(ext_inst_index);
74       if (ext_inst_key == DebugInfoDebugScope) {
75         uint32_t inlined_at = 0;
76         if (inst->num_words > kInlinedAtIndex)
77           inlined_at = inst->words[kInlinedAtIndex];
78         last_dbg_scope_ =
79             DebugScope(inst->words[kLexicalScopeIndex], inlined_at);
80         module()->SetContainsDebugScope();
81         return true;
82       }
83       if (ext_inst_key == DebugInfoDebugNoScope) {
84         last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt);
85         module()->SetContainsDebugScope();
86         return true;
87       }
88     }
89   }
90 
91   std::unique_ptr<Instruction> spv_inst(
92       new Instruction(module()->context(), *inst, std::move(dbg_line_info_)));
93   dbg_line_info_.clear();
94 
95   const char* src = source_.c_str();
96   spv_position_t loc = {inst_index_, 0, 0};
97 
98   // Handle function and basic block boundaries first, then normal
99   // instructions.
100   if (opcode == SpvOpFunction) {
101     if (function_ != nullptr) {
102       Error(consumer_, src, loc, "function inside function");
103       return false;
104     }
105     function_ = MakeUnique<Function>(std::move(spv_inst));
106   } else if (opcode == SpvOpFunctionEnd) {
107     if (function_ == nullptr) {
108       Error(consumer_, src, loc,
109             "OpFunctionEnd without corresponding OpFunction");
110       return false;
111     }
112     if (block_ != nullptr) {
113       Error(consumer_, src, loc, "OpFunctionEnd inside basic block");
114       return false;
115     }
116     function_->SetFunctionEnd(std::move(spv_inst));
117     module_->AddFunction(std::move(function_));
118     function_ = nullptr;
119   } else if (opcode == SpvOpLabel) {
120     if (function_ == nullptr) {
121       Error(consumer_, src, loc, "OpLabel outside function");
122       return false;
123     }
124     if (block_ != nullptr) {
125       Error(consumer_, src, loc, "OpLabel inside basic block");
126       return false;
127     }
128     block_ = MakeUnique<BasicBlock>(std::move(spv_inst));
129   } else if (IsTerminatorInst(opcode)) {
130     if (function_ == nullptr) {
131       Error(consumer_, src, loc, "terminator instruction outside function");
132       return false;
133     }
134     if (block_ == nullptr) {
135       Error(consumer_, src, loc, "terminator instruction outside basic block");
136       return false;
137     }
138     block_->AddInstruction(std::move(spv_inst));
139     function_->AddBasicBlock(std::move(block_));
140     block_ = nullptr;
141     last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt);
142   } else {
143     if (function_ == nullptr) {  // Outside function definition
144       SPIRV_ASSERT(consumer_, block_ == nullptr);
145       if (opcode == SpvOpCapability) {
146         module_->AddCapability(std::move(spv_inst));
147       } else if (opcode == SpvOpExtension) {
148         module_->AddExtension(std::move(spv_inst));
149       } else if (opcode == SpvOpExtInstImport) {
150         module_->AddExtInstImport(std::move(spv_inst));
151       } else if (opcode == SpvOpMemoryModel) {
152         module_->SetMemoryModel(std::move(spv_inst));
153       } else if (opcode == SpvOpEntryPoint) {
154         module_->AddEntryPoint(std::move(spv_inst));
155       } else if (opcode == SpvOpExecutionMode) {
156         module_->AddExecutionMode(std::move(spv_inst));
157       } else if (IsDebug1Inst(opcode)) {
158         module_->AddDebug1Inst(std::move(spv_inst));
159       } else if (IsDebug2Inst(opcode)) {
160         module_->AddDebug2Inst(std::move(spv_inst));
161       } else if (IsDebug3Inst(opcode)) {
162         module_->AddDebug3Inst(std::move(spv_inst));
163       } else if (IsAnnotationInst(opcode)) {
164         module_->AddAnnotationInst(std::move(spv_inst));
165       } else if (IsTypeInst(opcode)) {
166         module_->AddType(std::move(spv_inst));
167       } else if (IsConstantInst(opcode) || opcode == SpvOpVariable ||
168                  opcode == SpvOpUndef ||
169                  (opcode == SpvOpExtInst &&
170                   spvExtInstIsNonSemantic(inst->ext_inst_type))) {
171         module_->AddGlobalValue(std::move(spv_inst));
172       } else if (opcode == SpvOpExtInst &&
173                  spvExtInstIsDebugInfo(inst->ext_inst_type)) {
174         module_->AddExtInstDebugInfo(std::move(spv_inst));
175       } else {
176         Errorf(consumer_, src, loc,
177                "Unhandled inst type (opcode: %d) found outside function "
178                "definition.",
179                opcode);
180         return false;
181       }
182     } else {
183       if (opcode == SpvOpLoopMerge || opcode == SpvOpSelectionMerge)
184         last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt);
185       if (last_dbg_scope_.GetLexicalScope() != kNoDebugScope)
186         spv_inst->SetDebugScope(last_dbg_scope_);
187       if (opcode == SpvOpExtInst &&
188           spvExtInstIsDebugInfo(inst->ext_inst_type)) {
189         const uint32_t ext_inst_index = inst->words[kExtInstSetIndex];
190         if (inst->ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
191           const OpenCLDebugInfo100Instructions ext_inst_key =
192               OpenCLDebugInfo100Instructions(ext_inst_index);
193           switch (ext_inst_key) {
194             case OpenCLDebugInfo100DebugDeclare: {
195               if (block_ == nullptr)  // Inside function but outside blocks
196                 function_->AddDebugInstructionInHeader(std::move(spv_inst));
197               else
198                 block_->AddInstruction(std::move(spv_inst));
199               break;
200             }
201             case OpenCLDebugInfo100DebugValue: {
202               if (block_ == nullptr)  // Inside function but outside blocks
203                 function_->AddDebugInstructionInHeader(std::move(spv_inst));
204               else
205                 block_->AddInstruction(std::move(spv_inst));
206               break;
207             }
208             default: {
209               Errorf(consumer_, src, loc,
210                      "Debug info extension instruction other than DebugScope, "
211                      "DebugNoScope, DebugDeclare, and DebugValue found inside "
212                      "function",
213                      opcode);
214               return false;
215             }
216           }
217         } else {
218           const DebugInfoInstructions ext_inst_key =
219               DebugInfoInstructions(ext_inst_index);
220           switch (ext_inst_key) {
221             case DebugInfoDebugDeclare: {
222               if (block_ == nullptr)  // Inside function but outside blocks
223                 function_->AddDebugInstructionInHeader(std::move(spv_inst));
224               else
225                 block_->AddInstruction(std::move(spv_inst));
226               break;
227             }
228             case DebugInfoDebugValue: {
229               if (block_ == nullptr)  // Inside function but outside blocks
230                 function_->AddDebugInstructionInHeader(std::move(spv_inst));
231               else
232                 block_->AddInstruction(std::move(spv_inst));
233               break;
234             }
235             default: {
236               Errorf(consumer_, src, loc,
237                      "Debug info extension instruction other than DebugScope, "
238                      "DebugNoScope, DebugDeclare, and DebugValue found inside "
239                      "function",
240                      opcode);
241               return false;
242             }
243           }
244         }
245       } else {
246         if (block_ == nullptr) {  // Inside function but outside blocks
247           if (opcode != SpvOpFunctionParameter) {
248             Errorf(consumer_, src, loc,
249                    "Non-OpFunctionParameter (opcode: %d) found inside "
250                    "function but outside basic block",
251                    opcode);
252             return false;
253           }
254           function_->AddParameter(std::move(spv_inst));
255         } else {
256           block_->AddInstruction(std::move(spv_inst));
257         }
258       }
259     }
260   }
261   return true;
262 }
263 
264 // Resolves internal references among the module, functions, basic blocks, etc.
265 // This function should be called after adding all instructions.
EndModule()266 void IrLoader::EndModule() {
267   if (block_ && function_) {
268     // We're in the middle of a basic block, but the terminator is missing.
269     // Register the block anyway.  This lets us write tests with less
270     // boilerplate.
271     function_->AddBasicBlock(std::move(block_));
272     block_ = nullptr;
273   }
274   if (function_) {
275     // We're in the middle of a function, but the OpFunctionEnd is missing.
276     // Register the function anyway.  This lets us write tests with less
277     // boilerplate.
278     module_->AddFunction(std::move(function_));
279     function_ = nullptr;
280   }
281   for (auto& function : *module_) {
282     for (auto& bb : function) bb.SetParent(&function);
283   }
284 
285   // Copy any trailing Op*Line instruction into the module
286   module_->SetTrailingDbgLineInfo(std::move(dbg_line_info_));
287 }
288 
289 }  // namespace opt
290 }  // namespace spvtools
291