1 // Copyright (c) 2015-2016 The Khronos Group 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 // Source code for logical layout validation as described in section 2.4
16
17 #include "DebugInfo.h"
18 #include "NonSemanticShaderDebugInfo100.h"
19 #include "OpenCLDebugInfo100.h"
20 #include "source/opcode.h"
21 #include "source/operand.h"
22 #include "source/val/function.h"
23 #include "source/val/instruction.h"
24 #include "source/val/validate.h"
25 #include "source/val/validation_state.h"
26
27 namespace spvtools {
28 namespace val {
29 namespace {
30
31 // Module scoped instructions are processed by determining if the opcode
32 // is part of the current layout section. If it is not then the next sections is
33 // checked.
ModuleScopedInstructions(ValidationState_t & _,const Instruction * inst,spv::Op opcode)34 spv_result_t ModuleScopedInstructions(ValidationState_t& _,
35 const Instruction* inst, spv::Op opcode) {
36 switch (opcode) {
37 case spv::Op::OpExtInst:
38 if (spvExtInstIsDebugInfo(inst->ext_inst_type())) {
39 const uint32_t ext_inst_index = inst->word(4);
40 bool local_debug_info = false;
41 if (inst->ext_inst_type() == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
42 const OpenCLDebugInfo100Instructions ext_inst_key =
43 OpenCLDebugInfo100Instructions(ext_inst_index);
44 if (ext_inst_key == OpenCLDebugInfo100DebugScope ||
45 ext_inst_key == OpenCLDebugInfo100DebugNoScope ||
46 ext_inst_key == OpenCLDebugInfo100DebugDeclare ||
47 ext_inst_key == OpenCLDebugInfo100DebugValue) {
48 local_debug_info = true;
49 }
50 } else if (inst->ext_inst_type() ==
51 SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) {
52 const NonSemanticShaderDebugInfo100Instructions ext_inst_key =
53 NonSemanticShaderDebugInfo100Instructions(ext_inst_index);
54 if (ext_inst_key == NonSemanticShaderDebugInfo100DebugScope ||
55 ext_inst_key == NonSemanticShaderDebugInfo100DebugNoScope ||
56 ext_inst_key == NonSemanticShaderDebugInfo100DebugDeclare ||
57 ext_inst_key == NonSemanticShaderDebugInfo100DebugValue ||
58 ext_inst_key == NonSemanticShaderDebugInfo100DebugLine ||
59 ext_inst_key == NonSemanticShaderDebugInfo100DebugNoLine ||
60 ext_inst_key ==
61 NonSemanticShaderDebugInfo100DebugFunctionDefinition) {
62 local_debug_info = true;
63 }
64 } else {
65 const DebugInfoInstructions ext_inst_key =
66 DebugInfoInstructions(ext_inst_index);
67 if (ext_inst_key == DebugInfoDebugScope ||
68 ext_inst_key == DebugInfoDebugNoScope ||
69 ext_inst_key == DebugInfoDebugDeclare ||
70 ext_inst_key == DebugInfoDebugValue) {
71 local_debug_info = true;
72 }
73 }
74
75 if (local_debug_info) {
76 if (_.in_function_body() == false) {
77 // DebugScope, DebugNoScope, DebugDeclare, DebugValue must
78 // appear in a function body.
79 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
80 << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
81 << "of debug info extension must appear in a function "
82 << "body";
83 }
84 } else {
85 // Debug info extinst opcodes other than DebugScope, DebugNoScope,
86 // DebugDeclare, DebugValue must be placed between section 9 (types,
87 // constants, global variables) and section 10 (function
88 // declarations).
89 if (_.current_layout_section() < kLayoutTypes ||
90 _.current_layout_section() >= kLayoutFunctionDeclarations) {
91 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
92 << "Debug info extension instructions other than "
93 << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
94 << "must appear between section 9 (types, constants, "
95 << "global variables) and section 10 (function "
96 << "declarations)";
97 }
98 }
99 } else if (spvExtInstIsNonSemantic(inst->ext_inst_type())) {
100 // non-semantic extinst opcodes are allowed beginning in the types
101 // section, but since they must name a return type they cannot be the
102 // first instruction in the types section. Therefore check that we are
103 // already in it.
104 if (_.current_layout_section() < kLayoutTypes) {
105 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
106 << "Non-semantic OpExtInst must not appear before types "
107 << "section";
108 }
109 } else {
110 // otherwise they must be used in a block
111 if (_.current_layout_section() < kLayoutFunctionDefinitions) {
112 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
113 << spvOpcodeString(opcode) << " must appear in a block";
114 }
115 }
116 break;
117 default:
118 break;
119 }
120
121 while (_.IsOpcodeInCurrentLayoutSection(opcode) == false) {
122 if (_.IsOpcodeInPreviousLayoutSection(opcode)) {
123 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
124 << spvOpcodeString(opcode) << " is in an invalid layout section";
125 }
126
127 _.ProgressToNextLayoutSectionOrder();
128
129 switch (_.current_layout_section()) {
130 case kLayoutMemoryModel:
131 if (opcode != spv::Op::OpMemoryModel) {
132 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
133 << spvOpcodeString(opcode)
134 << " cannot appear before the memory model instruction";
135 }
136 break;
137 case kLayoutFunctionDeclarations:
138 // All module sections have been processed. Recursively call
139 // ModuleLayoutPass to process the next section of the module
140 return ModuleLayoutPass(_, inst);
141 default:
142 break;
143 }
144 }
145 return SPV_SUCCESS;
146 }
147
148 // Function declaration validation is performed by making sure that the
149 // FunctionParameter and FunctionEnd instructions only appear inside of
150 // functions. It also ensures that the Function instruction does not appear
151 // inside of another function. This stage ends when the first label is
152 // encountered inside of a function.
FunctionScopedInstructions(ValidationState_t & _,const Instruction * inst,spv::Op opcode)153 spv_result_t FunctionScopedInstructions(ValidationState_t& _,
154 const Instruction* inst,
155 spv::Op opcode) {
156 // Make sure we advance into the function definitions when we hit
157 // non-function declaration instructions.
158 if (_.current_layout_section() == kLayoutFunctionDeclarations &&
159 !_.IsOpcodeInCurrentLayoutSection(opcode)) {
160 _.ProgressToNextLayoutSectionOrder();
161
162 if (_.in_function_body()) {
163 if (auto error = _.current_function().RegisterSetFunctionDeclType(
164 FunctionDecl::kFunctionDeclDefinition)) {
165 return error;
166 }
167 }
168 }
169
170 if (_.IsOpcodeInCurrentLayoutSection(opcode)) {
171 switch (opcode) {
172 case spv::Op::OpFunction: {
173 if (_.in_function_body()) {
174 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
175 << "Cannot declare a function in a function body";
176 }
177 auto control_mask = inst->GetOperandAs<spv::FunctionControlMask>(2);
178 if (auto error =
179 _.RegisterFunction(inst->id(), inst->type_id(), control_mask,
180 inst->GetOperandAs<uint32_t>(3)))
181 return error;
182 if (_.current_layout_section() == kLayoutFunctionDefinitions) {
183 if (auto error = _.current_function().RegisterSetFunctionDeclType(
184 FunctionDecl::kFunctionDeclDefinition))
185 return error;
186 }
187 } break;
188
189 case spv::Op::OpFunctionParameter:
190 if (_.in_function_body() == false) {
191 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
192 << "Function parameter instructions must be in a "
193 "function body";
194 }
195 if (_.current_function().block_count() != 0) {
196 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
197 << "Function parameters must only appear immediately after "
198 "the function definition";
199 }
200 if (auto error = _.current_function().RegisterFunctionParameter(
201 inst->id(), inst->type_id()))
202 return error;
203 break;
204
205 case spv::Op::OpFunctionEnd:
206 if (_.in_function_body() == false) {
207 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
208 << "Function end instructions must be in a function body";
209 }
210 if (_.in_block()) {
211 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
212 << "Function end cannot be called in blocks";
213 }
214 if (_.current_function().block_count() == 0 &&
215 _.current_layout_section() == kLayoutFunctionDefinitions) {
216 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
217 << "Function declarations must appear before "
218 "function definitions.";
219 }
220 if (_.current_layout_section() == kLayoutFunctionDeclarations) {
221 if (auto error = _.current_function().RegisterSetFunctionDeclType(
222 FunctionDecl::kFunctionDeclDeclaration))
223 return error;
224 }
225 if (auto error = _.RegisterFunctionEnd()) return error;
226 break;
227
228 case spv::Op::OpLine:
229 case spv::Op::OpNoLine:
230 break;
231 case spv::Op::OpLabel:
232 // If the label is encountered then the current function is a
233 // definition so set the function to a declaration and update the
234 // module section
235 if (_.in_function_body() == false) {
236 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
237 << "Label instructions must be in a function body";
238 }
239 if (_.in_block()) {
240 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
241 << "A block must end with a branch instruction.";
242 }
243 break;
244
245 case spv::Op::OpExtInst:
246 if (spvExtInstIsDebugInfo(inst->ext_inst_type())) {
247 const uint32_t ext_inst_index = inst->word(4);
248 bool local_debug_info = false;
249 if (inst->ext_inst_type() == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
250 const OpenCLDebugInfo100Instructions ext_inst_key =
251 OpenCLDebugInfo100Instructions(ext_inst_index);
252 if (ext_inst_key == OpenCLDebugInfo100DebugScope ||
253 ext_inst_key == OpenCLDebugInfo100DebugNoScope ||
254 ext_inst_key == OpenCLDebugInfo100DebugDeclare ||
255 ext_inst_key == OpenCLDebugInfo100DebugValue) {
256 local_debug_info = true;
257 }
258 } else if (inst->ext_inst_type() ==
259 SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) {
260 const NonSemanticShaderDebugInfo100Instructions ext_inst_key =
261 NonSemanticShaderDebugInfo100Instructions(ext_inst_index);
262 if (ext_inst_key == NonSemanticShaderDebugInfo100DebugScope ||
263 ext_inst_key == NonSemanticShaderDebugInfo100DebugNoScope ||
264 ext_inst_key == NonSemanticShaderDebugInfo100DebugDeclare ||
265 ext_inst_key == NonSemanticShaderDebugInfo100DebugValue ||
266 ext_inst_key == NonSemanticShaderDebugInfo100DebugLine ||
267 ext_inst_key == NonSemanticShaderDebugInfo100DebugNoLine ||
268 ext_inst_key ==
269 NonSemanticShaderDebugInfo100DebugFunctionDefinition) {
270 local_debug_info = true;
271 }
272 } else {
273 const DebugInfoInstructions ext_inst_key =
274 DebugInfoInstructions(ext_inst_index);
275 if (ext_inst_key == DebugInfoDebugScope ||
276 ext_inst_key == DebugInfoDebugNoScope ||
277 ext_inst_key == DebugInfoDebugDeclare ||
278 ext_inst_key == DebugInfoDebugValue) {
279 local_debug_info = true;
280 }
281 }
282
283 if (local_debug_info) {
284 if (_.in_function_body() == false) {
285 // DebugScope, DebugNoScope, DebugDeclare, DebugValue must
286 // appear in a function body.
287 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
288 << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
289 << "of debug info extension must appear in a function "
290 << "body";
291 }
292 } else {
293 // Debug info extinst opcodes other than DebugScope, DebugNoScope,
294 // DebugDeclare, DebugValue must be placed between section 9 (types,
295 // constants, global variables) and section 10 (function
296 // declarations).
297 if (_.current_layout_section() < kLayoutTypes ||
298 _.current_layout_section() >= kLayoutFunctionDeclarations) {
299 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
300 << "Debug info extension instructions other than "
301 << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
302 << "must appear between section 9 (types, constants, "
303 << "global variables) and section 10 (function "
304 << "declarations)";
305 }
306 }
307 } else if (spvExtInstIsNonSemantic(inst->ext_inst_type())) {
308 // non-semantic extinst opcodes are allowed beginning in the types
309 // section, but must either be placed outside a function declaration,
310 // or inside a block.
311 if (_.current_layout_section() < kLayoutTypes) {
312 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
313 << "Non-semantic OpExtInst must not appear before types "
314 << "section";
315 } else if (_.in_function_body() && _.in_block() == false) {
316 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
317 << "Non-semantic OpExtInst within function definition must "
318 "appear in a block";
319 }
320 } else {
321 // otherwise they must be used in a block
322 if (_.in_block() == false) {
323 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
324 << spvOpcodeString(opcode) << " must appear in a block";
325 }
326 }
327 break;
328
329 default:
330 if (_.current_layout_section() == kLayoutFunctionDeclarations &&
331 _.in_function_body()) {
332 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
333 << "A function must begin with a label";
334 } else {
335 if (_.in_block() == false) {
336 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
337 << spvOpcodeString(opcode) << " must appear in a block";
338 }
339 }
340 break;
341 }
342 } else {
343 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
344 << spvOpcodeString(opcode)
345 << " cannot appear in a function declaration";
346 }
347 return SPV_SUCCESS;
348 }
349
350 } // namespace
351
352 // TODO(umar): Check linkage capabilities for function declarations
353 // TODO(umar): Better error messages
354 // NOTE: This function does not handle CFG related validation
355 // Performs logical layout validation. See Section 2.4
ModuleLayoutPass(ValidationState_t & _,const Instruction * inst)356 spv_result_t ModuleLayoutPass(ValidationState_t& _, const Instruction* inst) {
357 const spv::Op opcode = inst->opcode();
358
359 switch (_.current_layout_section()) {
360 case kLayoutCapabilities:
361 case kLayoutExtensions:
362 case kLayoutExtInstImport:
363 case kLayoutMemoryModel:
364 case kLayoutSamplerImageAddressMode:
365 case kLayoutEntryPoint:
366 case kLayoutExecutionMode:
367 case kLayoutDebug1:
368 case kLayoutDebug2:
369 case kLayoutDebug3:
370 case kLayoutAnnotations:
371 case kLayoutTypes:
372 if (auto error = ModuleScopedInstructions(_, inst, opcode)) return error;
373 break;
374 case kLayoutFunctionDeclarations:
375 case kLayoutFunctionDefinitions:
376 if (auto error = FunctionScopedInstructions(_, inst, opcode)) {
377 return error;
378 }
379 break;
380 }
381 return SPV_SUCCESS;
382 }
383
384 } // namespace val
385 } // namespace spvtools
386