• 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/ir_context.h"
23 #include "source/opt/log.h"
24 #include "source/opt/reflect.h"
25 #include "source/util/make_unique.h"
26 
27 static const uint32_t kExtInstSetIndex = 4;
28 static const uint32_t kLexicalScopeIndex = 5;
29 static const uint32_t kInlinedAtIndex = 6;
30 
31 namespace spvtools {
32 namespace opt {
33 
IrLoader(const MessageConsumer & consumer,Module * m)34 IrLoader::IrLoader(const MessageConsumer& consumer, Module* m)
35     : consumer_(consumer),
36       module_(m),
37       source_("<instruction>"),
38       inst_index_(0),
39       last_dbg_scope_(kNoDebugScope, kNoInlinedAt) {}
40 
IsLineInst(const spv_parsed_instruction_t * inst)41 bool IsLineInst(const spv_parsed_instruction_t* inst) {
42   const auto opcode = static_cast<SpvOp>(inst->opcode);
43   if (IsOpLineInst(opcode)) return true;
44   if (opcode != SpvOpExtInst) return false;
45   if (inst->ext_inst_type != SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100)
46     return false;
47   const uint32_t ext_inst_index = inst->words[kExtInstSetIndex];
48   const NonSemanticShaderDebugInfo100Instructions ext_inst_key =
49       NonSemanticShaderDebugInfo100Instructions(ext_inst_index);
50   return ext_inst_key == NonSemanticShaderDebugInfo100DebugLine ||
51          ext_inst_key == NonSemanticShaderDebugInfo100DebugNoLine;
52 }
53 
AddInstruction(const spv_parsed_instruction_t * inst)54 bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
55   ++inst_index_;
56   if (IsLineInst(inst)) {
57     module()->SetContainsDebugInfo();
58     last_line_inst_.reset();
59     dbg_line_info_.emplace_back(module()->context(), *inst, last_dbg_scope_);
60     return true;
61   }
62 
63   // If it is a DebugScope or DebugNoScope of debug extension, we do not
64   // create a new instruction, but simply keep the information in
65   // struct DebugScope.
66   const auto opcode = static_cast<SpvOp>(inst->opcode);
67   if (opcode == SpvOpExtInst && spvExtInstIsDebugInfo(inst->ext_inst_type)) {
68     const uint32_t ext_inst_index = inst->words[kExtInstSetIndex];
69     if (inst->ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 ||
70         inst->ext_inst_type ==
71             SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) {
72       const CommonDebugInfoInstructions ext_inst_key =
73           CommonDebugInfoInstructions(ext_inst_index);
74       if (ext_inst_key == CommonDebugInfoDebugScope) {
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()->SetContainsDebugInfo();
81         return true;
82       }
83       if (ext_inst_key == CommonDebugInfoDebugNoScope) {
84         last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt);
85         module()->SetContainsDebugInfo();
86         return true;
87       }
88     } else {
89       const DebugInfoInstructions ext_inst_key =
90           DebugInfoInstructions(ext_inst_index);
91       if (ext_inst_key == DebugInfoDebugScope) {
92         uint32_t inlined_at = 0;
93         if (inst->num_words > kInlinedAtIndex)
94           inlined_at = inst->words[kInlinedAtIndex];
95         last_dbg_scope_ =
96             DebugScope(inst->words[kLexicalScopeIndex], inlined_at);
97         module()->SetContainsDebugInfo();
98         return true;
99       }
100       if (ext_inst_key == DebugInfoDebugNoScope) {
101         last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt);
102         module()->SetContainsDebugInfo();
103         return true;
104       }
105     }
106   }
107 
108   std::unique_ptr<Instruction> spv_inst(
109       new Instruction(module()->context(), *inst, std::move(dbg_line_info_)));
110   if (!spv_inst->dbg_line_insts().empty()) {
111     if (extra_line_tracking_ &&
112         (!spv_inst->dbg_line_insts().back().IsNoLine())) {
113       last_line_inst_ = std::unique_ptr<Instruction>(
114           spv_inst->dbg_line_insts().back().Clone(module()->context()));
115       if (last_line_inst_->IsDebugLineInst())
116         last_line_inst_->SetResultId(module()->context()->TakeNextId());
117     }
118     dbg_line_info_.clear();
119   } else if (last_line_inst_ != nullptr) {
120     last_line_inst_->SetDebugScope(last_dbg_scope_);
121     spv_inst->dbg_line_insts().push_back(*last_line_inst_);
122     last_line_inst_ = std::unique_ptr<Instruction>(
123         spv_inst->dbg_line_insts().back().Clone(module()->context()));
124     if (last_line_inst_->IsDebugLineInst())
125       last_line_inst_->SetResultId(module()->context()->TakeNextId());
126   }
127 
128   const char* src = source_.c_str();
129   spv_position_t loc = {inst_index_, 0, 0};
130 
131   // Handle function and basic block boundaries first, then normal
132   // instructions.
133   if (opcode == SpvOpFunction) {
134     if (function_ != nullptr) {
135       Error(consumer_, src, loc, "function inside function");
136       return false;
137     }
138     function_ = MakeUnique<Function>(std::move(spv_inst));
139   } else if (opcode == SpvOpFunctionEnd) {
140     if (function_ == nullptr) {
141       Error(consumer_, src, loc,
142             "OpFunctionEnd without corresponding OpFunction");
143       return false;
144     }
145     if (block_ != nullptr) {
146       Error(consumer_, src, loc, "OpFunctionEnd inside basic block");
147       return false;
148     }
149     function_->SetFunctionEnd(std::move(spv_inst));
150     module_->AddFunction(std::move(function_));
151     function_ = nullptr;
152   } else if (opcode == SpvOpLabel) {
153     if (function_ == nullptr) {
154       Error(consumer_, src, loc, "OpLabel outside function");
155       return false;
156     }
157     if (block_ != nullptr) {
158       Error(consumer_, src, loc, "OpLabel inside basic block");
159       return false;
160     }
161     block_ = MakeUnique<BasicBlock>(std::move(spv_inst));
162   } else if (spvOpcodeIsBlockTerminator(opcode)) {
163     if (function_ == nullptr) {
164       Error(consumer_, src, loc, "terminator instruction outside function");
165       return false;
166     }
167     if (block_ == nullptr) {
168       Error(consumer_, src, loc, "terminator instruction outside basic block");
169       return false;
170     }
171     if (last_dbg_scope_.GetLexicalScope() != kNoDebugScope)
172       spv_inst->SetDebugScope(last_dbg_scope_);
173     block_->AddInstruction(std::move(spv_inst));
174     function_->AddBasicBlock(std::move(block_));
175     block_ = nullptr;
176     last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt);
177     last_line_inst_.reset();
178     dbg_line_info_.clear();
179   } else {
180     if (function_ == nullptr) {  // Outside function definition
181       SPIRV_ASSERT(consumer_, block_ == nullptr);
182       if (opcode == SpvOpCapability) {
183         module_->AddCapability(std::move(spv_inst));
184       } else if (opcode == SpvOpExtension) {
185         module_->AddExtension(std::move(spv_inst));
186       } else if (opcode == SpvOpExtInstImport) {
187         module_->AddExtInstImport(std::move(spv_inst));
188       } else if (opcode == SpvOpMemoryModel) {
189         module_->SetMemoryModel(std::move(spv_inst));
190       } else if (opcode == SpvOpSamplerImageAddressingModeNV) {
191         module_->SetSampledImageAddressMode(std::move(spv_inst));
192       } else if (opcode == SpvOpEntryPoint) {
193         module_->AddEntryPoint(std::move(spv_inst));
194       } else if (opcode == SpvOpExecutionMode ||
195                  opcode == SpvOpExecutionModeId) {
196         module_->AddExecutionMode(std::move(spv_inst));
197       } else if (IsDebug1Inst(opcode)) {
198         module_->AddDebug1Inst(std::move(spv_inst));
199       } else if (IsDebug2Inst(opcode)) {
200         module_->AddDebug2Inst(std::move(spv_inst));
201       } else if (IsDebug3Inst(opcode)) {
202         module_->AddDebug3Inst(std::move(spv_inst));
203       } else if (IsAnnotationInst(opcode)) {
204         module_->AddAnnotationInst(std::move(spv_inst));
205       } else if (IsTypeInst(opcode)) {
206         module_->AddType(std::move(spv_inst));
207       } else if (IsConstantInst(opcode) || opcode == SpvOpVariable ||
208                  opcode == SpvOpUndef) {
209         module_->AddGlobalValue(std::move(spv_inst));
210       } else if (opcode == SpvOpExtInst &&
211                  spvExtInstIsDebugInfo(inst->ext_inst_type)) {
212         module_->AddExtInstDebugInfo(std::move(spv_inst));
213       } else if (opcode == SpvOpExtInst &&
214                  spvExtInstIsNonSemantic(inst->ext_inst_type)) {
215         // If there are no functions, add the non-semantic instructions to the
216         // global values. Otherwise append it to the list of the last function.
217         auto func_begin = module_->begin();
218         auto func_end = module_->end();
219         if (func_begin == func_end) {
220           module_->AddGlobalValue(std::move(spv_inst));
221         } else {
222           (--func_end)->AddNonSemanticInstruction(std::move(spv_inst));
223         }
224       } else {
225         Errorf(consumer_, src, loc,
226                "Unhandled inst type (opcode: %d) found outside function "
227                "definition.",
228                opcode);
229         return false;
230       }
231     } else {
232       if (opcode == SpvOpLoopMerge || opcode == SpvOpSelectionMerge)
233         last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt);
234       if (last_dbg_scope_.GetLexicalScope() != kNoDebugScope)
235         spv_inst->SetDebugScope(last_dbg_scope_);
236       if (opcode == SpvOpExtInst &&
237           spvExtInstIsDebugInfo(inst->ext_inst_type)) {
238         const uint32_t ext_inst_index = inst->words[kExtInstSetIndex];
239         if (inst->ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
240           const OpenCLDebugInfo100Instructions ext_inst_key =
241               OpenCLDebugInfo100Instructions(ext_inst_index);
242           switch (ext_inst_key) {
243             case OpenCLDebugInfo100DebugDeclare: {
244               if (block_ == nullptr)  // Inside function but outside blocks
245                 function_->AddDebugInstructionInHeader(std::move(spv_inst));
246               else
247                 block_->AddInstruction(std::move(spv_inst));
248               break;
249             }
250             case OpenCLDebugInfo100DebugValue: {
251               if (block_ == nullptr)  // Inside function but outside blocks
252                 function_->AddDebugInstructionInHeader(std::move(spv_inst));
253               else
254                 block_->AddInstruction(std::move(spv_inst));
255               break;
256             }
257             default: {
258               Errorf(consumer_, src, loc,
259                      "Debug info extension instruction other than DebugScope, "
260                      "DebugNoScope, DebugFunctionDefinition, DebugDeclare, and "
261                      "DebugValue found inside function",
262                      opcode);
263               return false;
264             }
265           }
266         } else if (inst->ext_inst_type ==
267                    SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) {
268           const NonSemanticShaderDebugInfo100Instructions ext_inst_key =
269               NonSemanticShaderDebugInfo100Instructions(ext_inst_index);
270           switch (ext_inst_key) {
271             case NonSemanticShaderDebugInfo100DebugDeclare:
272             case NonSemanticShaderDebugInfo100DebugValue:
273             case NonSemanticShaderDebugInfo100DebugScope:
274             case NonSemanticShaderDebugInfo100DebugNoScope:
275             case NonSemanticShaderDebugInfo100DebugFunctionDefinition: {
276               if (block_ == nullptr) {  // Inside function but outside blocks
277                 Errorf(consumer_, src, loc,
278                        "Debug info extension instruction found inside function "
279                        "but outside block",
280                        opcode);
281               } else {
282                 block_->AddInstruction(std::move(spv_inst));
283               }
284               break;
285             }
286             default: {
287               Errorf(consumer_, src, loc,
288                      "Debug info extension instruction other than DebugScope, "
289                      "DebugNoScope, DebugDeclare, and DebugValue found inside "
290                      "function",
291                      opcode);
292               return false;
293             }
294           }
295         } else {
296           const DebugInfoInstructions ext_inst_key =
297               DebugInfoInstructions(ext_inst_index);
298           switch (ext_inst_key) {
299             case DebugInfoDebugDeclare: {
300               if (block_ == nullptr)  // Inside function but outside blocks
301                 function_->AddDebugInstructionInHeader(std::move(spv_inst));
302               else
303                 block_->AddInstruction(std::move(spv_inst));
304               break;
305             }
306             case DebugInfoDebugValue: {
307               if (block_ == nullptr)  // Inside function but outside blocks
308                 function_->AddDebugInstructionInHeader(std::move(spv_inst));
309               else
310                 block_->AddInstruction(std::move(spv_inst));
311               break;
312             }
313             default: {
314               Errorf(consumer_, src, loc,
315                      "Debug info extension instruction other than DebugScope, "
316                      "DebugNoScope, DebugDeclare, and DebugValue found inside "
317                      "function",
318                      opcode);
319               return false;
320             }
321           }
322         }
323       } else {
324         if (block_ == nullptr) {  // Inside function but outside blocks
325           if (opcode != SpvOpFunctionParameter) {
326             Errorf(consumer_, src, loc,
327                    "Non-OpFunctionParameter (opcode: %d) found inside "
328                    "function but outside basic block",
329                    opcode);
330             return false;
331           }
332           function_->AddParameter(std::move(spv_inst));
333         } else {
334           block_->AddInstruction(std::move(spv_inst));
335         }
336       }
337     }
338   }
339   return true;
340 }
341 
342 // Resolves internal references among the module, functions, basic blocks, etc.
343 // This function should be called after adding all instructions.
EndModule()344 void IrLoader::EndModule() {
345   if (block_ && function_) {
346     // We're in the middle of a basic block, but the terminator is missing.
347     // Register the block anyway.  This lets us write tests with less
348     // boilerplate.
349     function_->AddBasicBlock(std::move(block_));
350     block_ = nullptr;
351   }
352   if (function_) {
353     // We're in the middle of a function, but the OpFunctionEnd is missing.
354     // Register the function anyway.  This lets us write tests with less
355     // boilerplate.
356     module_->AddFunction(std::move(function_));
357     function_ = nullptr;
358   }
359   for (auto& function : *module_) {
360     for (auto& bb : function) bb.SetParent(&function);
361   }
362 
363   // Copy any trailing Op*Line instruction into the module
364   module_->SetTrailingDbgLineInfo(std::move(dbg_line_info_));
365 }
366 
367 }  // namespace opt
368 }  // namespace spvtools
369