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