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 case spv::Op::OpExtInstWithForwardRefsKHR:
39 if (spvExtInstIsDebugInfo(inst->ext_inst_type())) {
40 const uint32_t ext_inst_index = inst->word(4);
41 bool local_debug_info = false;
42 if (inst->ext_inst_type() == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
43 const OpenCLDebugInfo100Instructions ext_inst_key =
44 OpenCLDebugInfo100Instructions(ext_inst_index);
45 if (ext_inst_key == OpenCLDebugInfo100DebugScope ||
46 ext_inst_key == OpenCLDebugInfo100DebugNoScope ||
47 ext_inst_key == OpenCLDebugInfo100DebugDeclare ||
48 ext_inst_key == OpenCLDebugInfo100DebugValue) {
49 local_debug_info = true;
50 }
51 } else if (inst->ext_inst_type() ==
52 SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) {
53 const NonSemanticShaderDebugInfo100Instructions ext_inst_key =
54 NonSemanticShaderDebugInfo100Instructions(ext_inst_index);
55 if (ext_inst_key == NonSemanticShaderDebugInfo100DebugScope ||
56 ext_inst_key == NonSemanticShaderDebugInfo100DebugNoScope ||
57 ext_inst_key == NonSemanticShaderDebugInfo100DebugDeclare ||
58 ext_inst_key == NonSemanticShaderDebugInfo100DebugValue ||
59 ext_inst_key == NonSemanticShaderDebugInfo100DebugLine ||
60 ext_inst_key == NonSemanticShaderDebugInfo100DebugNoLine ||
61 ext_inst_key ==
62 NonSemanticShaderDebugInfo100DebugFunctionDefinition) {
63 local_debug_info = true;
64 }
65 } else {
66 const DebugInfoInstructions ext_inst_key =
67 DebugInfoInstructions(ext_inst_index);
68 if (ext_inst_key == DebugInfoDebugScope ||
69 ext_inst_key == DebugInfoDebugNoScope ||
70 ext_inst_key == DebugInfoDebugDeclare ||
71 ext_inst_key == DebugInfoDebugValue) {
72 local_debug_info = true;
73 }
74 }
75
76 if (local_debug_info) {
77 if (_.in_function_body() == false) {
78 // TODO - Print the actual name of the instruction as this list is
79 // not complete (see ext_inst_name in ValidateExtInst() for example)
80 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
81 << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
82 << "of debug info extension must appear in a function "
83 << "body";
84 }
85 } else {
86 // Debug info extinst opcodes other than DebugScope, DebugNoScope,
87 // DebugDeclare, DebugValue must be placed between section 9 (types,
88 // constants, global variables) and section 10 (function
89 // declarations).
90 if (_.current_layout_section() < kLayoutTypes ||
91 _.current_layout_section() >= kLayoutFunctionDeclarations) {
92 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
93 << "Debug info extension instructions other than "
94 << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
95 << "must appear between section 9 (types, constants, "
96 << "global variables) and section 10 (function "
97 << "declarations)";
98 }
99 }
100 } else if (spvExtInstIsNonSemantic(inst->ext_inst_type())) {
101 // non-semantic extinst opcodes are allowed beginning in the types
102 // section, but since they must name a return type they cannot be the
103 // first instruction in the types section. Therefore check that we are
104 // already in it.
105 if (_.current_layout_section() < kLayoutTypes) {
106 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
107 << "Non-semantic OpExtInst must not appear before types "
108 << "section";
109 }
110 } else {
111 // otherwise they must be used in a block
112 if (_.current_layout_section() < kLayoutFunctionDefinitions) {
113 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
114 << spvOpcodeString(opcode) << " must appear in a block";
115 }
116 }
117 break;
118 default:
119 break;
120 }
121
122 while (_.IsOpcodeInCurrentLayoutSection(opcode) == false) {
123 if (_.IsOpcodeInPreviousLayoutSection(opcode)) {
124 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
125 << spvOpcodeString(opcode) << " is in an invalid layout section";
126 }
127
128 _.ProgressToNextLayoutSectionOrder();
129
130 switch (_.current_layout_section()) {
131 case kLayoutMemoryModel:
132 if (opcode != spv::Op::OpMemoryModel) {
133 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
134 << spvOpcodeString(opcode)
135 << " cannot appear before the memory model instruction";
136 }
137 break;
138 case kLayoutFunctionDeclarations:
139 // All module sections have been processed. Recursively call
140 // ModuleLayoutPass to process the next section of the module
141 return ModuleLayoutPass(_, inst);
142 default:
143 break;
144 }
145 }
146 return SPV_SUCCESS;
147 }
148
149 // Function declaration validation is performed by making sure that the
150 // FunctionParameter and FunctionEnd instructions only appear inside of
151 // functions. It also ensures that the Function instruction does not appear
152 // inside of another function. This stage ends when the first label is
153 // encountered inside of a function.
FunctionScopedInstructions(ValidationState_t & _,const Instruction * inst,spv::Op opcode)154 spv_result_t FunctionScopedInstructions(ValidationState_t& _,
155 const Instruction* inst,
156 spv::Op opcode) {
157 // Make sure we advance into the function definitions when we hit
158 // non-function declaration instructions.
159 if (_.current_layout_section() == kLayoutFunctionDeclarations &&
160 !_.IsOpcodeInCurrentLayoutSection(opcode)) {
161 _.ProgressToNextLayoutSectionOrder();
162
163 if (_.in_function_body()) {
164 if (auto error = _.current_function().RegisterSetFunctionDeclType(
165 FunctionDecl::kFunctionDeclDefinition)) {
166 return error;
167 }
168 }
169 }
170
171 if (_.IsOpcodeInCurrentLayoutSection(opcode)) {
172 switch (opcode) {
173 case spv::Op::OpFunction: {
174 if (_.in_function_body()) {
175 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
176 << "Cannot declare a function in a function body";
177 }
178 auto control_mask = inst->GetOperandAs<spv::FunctionControlMask>(2);
179 if (auto error =
180 _.RegisterFunction(inst->id(), inst->type_id(), control_mask,
181 inst->GetOperandAs<uint32_t>(3)))
182 return error;
183 if (_.current_layout_section() == kLayoutFunctionDefinitions) {
184 if (auto error = _.current_function().RegisterSetFunctionDeclType(
185 FunctionDecl::kFunctionDeclDefinition))
186 return error;
187 }
188 } break;
189
190 case spv::Op::OpFunctionParameter:
191 if (_.in_function_body() == false) {
192 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
193 << "Function parameter instructions must be in a "
194 "function body";
195 }
196 if (_.current_function().block_count() != 0) {
197 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
198 << "Function parameters must only appear immediately after "
199 "the function definition";
200 }
201 if (auto error = _.current_function().RegisterFunctionParameter(
202 inst->id(), inst->type_id()))
203 return error;
204 break;
205
206 case spv::Op::OpFunctionEnd:
207 if (_.in_function_body() == false) {
208 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
209 << "Function end instructions must be in a function body";
210 }
211 if (_.in_block()) {
212 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
213 << "Function end cannot be called in blocks";
214 }
215 if (_.current_function().block_count() == 0 &&
216 _.current_layout_section() == kLayoutFunctionDefinitions) {
217 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
218 << "Function declarations must appear before "
219 "function definitions.";
220 }
221 if (_.current_layout_section() == kLayoutFunctionDeclarations) {
222 if (auto error = _.current_function().RegisterSetFunctionDeclType(
223 FunctionDecl::kFunctionDeclDeclaration))
224 return error;
225 }
226 if (auto error = _.RegisterFunctionEnd()) return error;
227 break;
228
229 case spv::Op::OpLine:
230 case spv::Op::OpNoLine:
231 break;
232 case spv::Op::OpLabel:
233 // If the label is encountered then the current function is a
234 // definition so set the function to a declaration and update the
235 // module section
236 if (_.in_function_body() == false) {
237 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
238 << "Label instructions must be in a function body";
239 }
240 if (_.in_block()) {
241 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
242 << "A block must end with a branch instruction.";
243 }
244 break;
245
246 case spv::Op::OpExtInst:
247 case spv::Op::OpExtInstWithForwardRefsKHR:
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 spv::Op 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